【问题标题】:How to represent binary tree?如何表示二叉树?
【发布时间】:2016-01-14 08:01:02
【问题描述】:

用列表表示的序列自然地泛化为表示具有以下特征的序列 元素本身可能是序列。例如,我们可以认为(cons (list 1 2) (list 3 4))构造的对象((1 2) 3 4)。序列的元素是树的分支,本身是序列的元素是子树。

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

将列表结构视为一棵树。

 /\\
/\ 3 4 
1 2

为什么不是下面这个?

  / \
 /\ /\
1 2 3 4

【问题讨论】:

    标签: tree scheme


    【解决方案1】:

    在源自原始 Lisp 的语言中,例如 Scheme,您没有 列表或树作为原始数据结构,但仅限于 cons 单元格, 可以以不同方式使用来表示更复杂的数据 结构。

    例如,没有什么可以阻止您将数字序列表示为 不正确的列表,即将序列 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 叉树,其中信息存在于每个节点或 在树叶里,

    4. 二叉树或多叉树,其中信息是一个列表,或更复杂的结构(例如另一棵树),

    等等

    您可以为手头的问题选择正确的表示形式。 例如,在上面的情况 (2) 中,这比情况 (1) 更常见,您可以将树表示为三个元素(信息、左子树、右子树)的列表(在这个在这种情况下,您可以选择正确的列表或不正确的列表),或者您可以使用具有三个字段的结构,甚至可以使用具有三个元素的数组。

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

    【讨论】:

    • 我不明白为什么我们需要在 '((1 2) 3 4) 中只使用括号 (1 2) 而不是 3 and 4
    • 这仅仅是因为在 Lisp 语言中打印列表的约定。约定是:“如果某些内容以'() 结尾,则将其打印为列表”。例如:(cons (cons 1 (cons 2 '()) '()) 打印为'((1 2)),因为(cons 1 (cons 2 '()))'() 结尾,对于外部cons 也是如此。相反,如果某些内容以“非'()”结尾,则使用点符号。例如,(cons 1 (cons 2 3)) 打印为(1 2 . 3)。而(cons (cons 1 2) (cons 3 4)) 打印为((1 . 2) . (3 . 4))
    • "在可能的情况下,列表表示法优于点表示法。因此,使用以下算法打印 cons x: 1. 打印左括号。 2. 打印 x 的汽车。 3.如果x的cdr本身是一个cons,则将其设为当前cons(即x变成那个cons),打印一个空格,重新进入第2步。 4.如果x的cdr是不为空,打印一个空格、一个点、一个空格和 x 的 cdr。5. 打印一个右括号。 (参见 documentation 了解 Common Lisp,也适用于 Scheme 中的列表)。
    【解决方案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 树,你在查找中迭代树,你通常只需要一个父级。因此。一对可能是父节点和这个节点的值。

    【讨论】:

    • 它们的树形图像与您的不同。我不明白为什么?
    • 我不明白为什么我们需要在'((1 2) 3 4) 中只使用括号 (1 2) 而不是 3 和 4?
    • @ivan_petrushenko 图 2.3 不是二叉树。它说您可以将列表结构视为一棵树,并显示一棵具有任意子节点的树。您也可以将其视为二叉树,然后它看起来就像我的视图,看起来像点和框,其中每个分支都是cons。我制作的树程序也适用于这些程序。请注意,accumulate-tree 与第 104 页上的 count-leaves 非常相似,只是我使用树形程序来提高可读性。
    • 但我说的是图 2.6,而不是 2.3
    • @ivan_petrushenko 我的意思是 2.6。 2.3 不存在。很抱歉造成混淆。
    猜你喜欢
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多