我正在阅读Paul Graham撰写的“ANSI Common Lisp”,价格为3.8美元(第40页):
“Conses也可以被视为二叉树,汽车代表正确的子树,cdr代表左侧。”
对我而言,听起来像“右”和“左”在相反的位置被错误地使用了......然后我看了一下在线勘误,但它不是那里列出的项目之一......
http://www.paulgraham.com/ancomliser.html
任何人都可以帮忙解释一下吗?
顺便说一下,在下一页(第41页),保罗说“没有内部节点的二叉树没有用处。”我也不完全理解它。 “没有内部节点”是什么意思?一个深层嵌套的列表可以拥有你想要的内部/内部节点(即,conses),为什么他说“没有”?或者他只是意味着这些内部节点(如果存在)不包含原子值?
谢谢, /布鲁因
答案 0 :(得分:3)
在Lisp语法中,car
确实是右半部分cdr
的左半部分。
对于内部节点,我认为Graham意味着未标记的内部节点。例如。你会经常遇到像
这样的树(+ (* x y) z)
应该被认为是由三元组构建的树,即使是以对形式实现的,也不是形式的树
((a . b) . (c . d))
答案 1 :(得分:3)
Conses也可以被认为是汽车的二叉树 表示正确的子树和表示左侧的cdr。
你认为这似乎是非常规的。应该说car
代表 left 子树,而cdr
代表 right 子树。也就是说,从cons单元构建的树(以及列表)是内涵数据结构。我们决定如何使用cons单元表示结构,然后根据该表示进行思考,而不是考虑cons单元。因此,当我们编写列表处理代码时,我们更喜欢
(defun mapcar1 (fn list)
(cons (funcall fn (first list))
(mapcar fn (rest list))))
到
(defun mapcar1 (fn list)
(cons (funcall fn (car list))
(mapcar fn (cdr list))))
因为我们认为列表具有第一个元素,并且列表中存在 rest ,即使两者都有效。由于实施,car
和cdr
也会起作用,这只是巧合。 (当然,当我们注意到我们有名为mapcar
和nthcdr
而不是map
的函数时,这是一个漏洞抽象(好吧,是一个map
函数,但它有点不同)和nthrest
或nthtail
。
同样,我们必须选择使用cons单元表示二叉树。无论你是否真的,
。(defun make-tree (left right)
(cons left right))
(defun left (tree)
(car tree))
(defun right (tree)
(cdr tree))
或
(defun make-tree (left right)
(cons right left))
(defun left (tree)
(cdr tree))
(defun right (tree)
(car tree))
因为您应该使用make-tree
,left
和right
而不是cons
,car
和{ {1}}当您使用树木时。
没有内部节点的二叉树没有多大用处。
他指的是二进制树,其内部节点不具有自己的值。例如,在二叉搜索树中,节点不仅具有左子树和右子树,它具有关联的值(或元素)。二叉搜索树节点实际上是三元组(元素,左,右),而不是一对(左,右)。一些问题可以通过二进制树来解决,二进制树的节点没有相关的值,但是对于许多问题,除了一个值之外,你还希望节点有两个指针(左右子树)。 / p>
答案 2 :(得分:2)
如果您使用某种形式的节点表示(二进制)树,我们有几种可能的方法在Common Lisp中表示它们。
我们可以定义一个节点结构:
(defstruct node left right)
然后我们有一个函数MAKE-NODE
。
我们可以定义一个节点类:
(defclass node ()
(left right))
节点将使用(make-instance 'node)
。
我们可以用列表创建节点:
(defun make-node (left right)
(list left right))
上面使用了两个利弊细胞。
我们可以只使用一个cons单元格为二元树创建一个小的节点:
(defun make-node (left right)
(cons left right))
我们可以将节点作为向量:
(defun make-node (left right)
(vector left right))
有很多种可能性。如果节点还应该有其他信息,那么单一的cons单元方法是不够的。类似于结构或类的东西很好,因为数据项可以包含更多信息,并且对象知道它的类型:我们可以轻松地询问(node-p something)
并获得有用的答案。
为您要编写的任何稍高级软件选择正确数据结构的样式规则:
答案 3 :(得分:2)
国际海事组织,如果案文简单地说的话会更好:
Conses也可以被视为二叉树,汽车代表一个子树,cdr代表其他子树。
左边选择哪个,右边选择哪个是任意的。 (当然,一致性等)或许文本已经引入了具体的表述?或许它之后会这样做,需要参考哪个是哪个?如果不是 - 如果那个陈述完全存在,那么我认为没有理由选择双方。
答案 4 :(得分:2)
当他断言汽车是正确的并且司机是左边时,他只是很可爱?
回想一下,汽车/ cdr最初是在IBM 704上产生的。在那台机器上,汽车(即地址部分)的单词是右侧。这个one of the 704 manuals第8页的图4说明了这一点。所以我猜他的演讲有一些历史的有效性。
但我很好奇他是否真的有使用他的左/右惯例绘制的'(a b c d)等列表的插图。
答案 5 :(得分:1)
这是一个错误。它出错的原因是conses对应于打印的符号,并且打印的符号以特定的方式从左到右。
示例:
(a b c d) <==> (a . (b . (c . (d . nil))))
这对应于树结构:
.
/ \
a .
/ \
b .
/ \
c .
/ \
d nil
树不是简单的图形;孩子们被命令。
如果您说(a . b)
是包含左子b
和右子a
的节点,则违反您正在使用的符号的约定,左右的含义,以及你正在使用的写作方向。
如果我们讨论Lisp,符号:car
- s打印在左侧,在列表的其余部分之前。混合起来并没有恰当地描述Lisp中的情况,我们必须考虑到所有内容,包括符号表达式和内部结构之间的对应关系。
如果您使用Lisp conses实现二进制数据结构,并且您不关心与Lisp的打印表示的任何对应关系,您可以左右分配car
和cdr
无论哪种方式当然,你喜欢这个算法,算法也会解决。但是,代码中的约定并不描述Lisp语言。