如何表示二叉树?

时间:2016-01-14 08:01:03

标签: tree scheme

根据列表表示的序列自然地概括为表示其序列的序列 元素本身可以是序列。例如,我们可以看到由((1 2) 3 4)构造的对象(cons (list 1 2) (list 3 4))。序列的元素是树的分支,本身序列的元素是子树。

我不明白。我想看((1 2) (3 4))和二叉树,但这是三元树(不是二进制)。

列表结构被视为树。

 /\\
/\ 3 4 
1 2

为什么它不是以下?

  / \
 /\ /\
1 2 3 4

2 个答案:

答案 0 :(得分:4)

在源自类似Scheme的原始Lisp的语言中,您没有 列表或树作为原始数据结构,但只有 cons cells , 可以用不同的方式来表示更复杂的数据 结构。

例如,没有什么能阻止你将一系列数字表示为 不正确的清单,即将序列1 2 3 4表示为:

(cons 1 (cons 2 (cons 3 4)))  ;  => '(1 2 3 . 4)

[*|*]--->[*|*]--->[*|*]--->4
 |        |        |
 v        v        v
 1        2        3

比通常的正确列表表示更有效:

(cons 1 (cons 2 (cons 3 (cons 4 '())))) = (list 1 2 3 4)  ;  => '(1 2 3 4)

[*|*]--->[*|*]--->[*|*]--->[*|*]--->()
 |        |        |        |
 v        v        v        v
 1        2        3        4

(例如,考虑一个您必须管理数百万的应用程序 小清单。)

通常使用正确的列表,因为绝大多数原语 函数只为它们定义(例如,如果你尝试,你会得到一个错误 反转'(1 2 3.4)),因此使用起来更方便。

另一方面,对于树木来说,情况更复杂,因为你 可以有不同种类的树,例如:

  1. 二叉树,其中信息仅存在于树叶中(如示例所示),

  2. 二进制树,其中信息出现在每个节点中,

  3. n-ary树,其中的信息存在于每个节点或 在树叶里,

  4. 二进制或n-ary树,其中信息是列表,或更复杂的结构(例如另一棵树),

  5. 由您来决定手头问题的正确表示。 例如,在上面的情况(2)中,这比情况(1)更常见,您可以将树表示为三个元素的列表(信息,左子树,右子树)(并且在此你可以选择一个正确的列表或一个不正确的列表,或者你可以使用一个包含三个字段的结构,甚至是一个包含三个元素的数组。

    总结一下,重要的是以这种方式定义一棵树 最适合您的需求(可能会看到是否有预定义的功能或可用的库 已经提供了你需要的运算符),然后定义了基本运算符来处理它,比如在answer of Sylwester中运算符来构建树并使用它的组件,而总是使用它们来编写你的程序。通过这种方式,您可以获得Abstract Data Type方法的所有常见好处,例如,您可以在不修改程序的情况下更改树的表示形式。

答案 1 :(得分:2)

为了更好地理解,将列表翻译成点对:

(cons (list 1 2) (list 3 4)) ; ==
((1 2) 3 4) ==
((1 . (2 . '())) . (3 . (4 . '()))) ; ==

     /\
    /  \
   /\   \
  /  \  /\ 
1   /\  3/\
   2  ()4 ()

您正在绘制的树将是:

((1 . 2) . (3 . 4)) ; but the general way of displaying it would be
((1 . 2) 3 . 4)

我假设一对是汽车正确且cdr是左侧的节点。基本上是:

(define make-tree cons)
(define tree-right car)
(define tree-left cdr)
(define tree? pair?)
(define *tree-null* '())

现在你可以这样建模这样的树:

(define make-tree list)
(define tree-right car)
(define tree-left cadr)
(define tree? list?)
(define *tree-null* '())

然后同一棵树看起来像这样:

((1 2) (3 4))

这并不重要,但第一个例子是常用的方式,因为它占用的空间更少。无论如何,这些都是一样的:

(define (accumulate-tree tree term combiner null-value)
  (let rec ((tree tree))
    (cond ((eq? *tree-null* tree) null-value)
          ((not (tree? tree)) (term tree))
          (else (combiner (rec (tree-left tree)) 
                          (rec (tree-right tree)))))))

(define (copy-tree tree)
  (accumulate-tree tree values make-tree *tree-null*))

(define (aritmetric-sum-tree tree)
  (accumulate-tree tree values + 0))

(define (reverse-tree tree)
  (accumulate-tree tree 
                   values
                   (lambda (left right) (make-tree right left))
                   *tree-null*))

修改

SICP仅提供不同的方式来查看相同的结构,而不是二叉树。节点是子节点列表,子节点是列表是新节点。了解盒子并且链式缺点有一种奇怪的显示方式,这一点非常重要。注意框子是如何与我的树相似的。

了解使用cons可以为任何抽象数据结构建模,在创建自己的数据结构时,您将更改如何将元素映射到cons,这一点非常重要。因此,相同的列表结构可能代表其他东西,具体取决于您如何使用它们。例如。如果你有一个LZW树,你在查找中迭代树,你通常只需要一个父。从而。一对可能是父对象,这个节点值。