【问题标题】:Traversing a binary tree using linked list使用链表遍历二叉树
【发布时间】:2017-08-23 13:29:57
【问题描述】:

我正在尝试使用链表对二叉树进行前序遍历。

class BTNode:
"""A node in a binary tree."""

    def __init__(self: 'BTNode', item: object, 
             left: 'BTNode' =None, right: 'BTNode' =None) -> None:

        self.item, self.left, self.right = item, left, right


class LLNode:
    """A node in a linked list."""

    def __init__(self: 'LLNode', item: object, link: 'LLNode' =None) -> None:

        self.item, self.link = item, link

    def __str__(self: 'LLNode') -> str:
        """Return an informative string showing self

        >>> b = LLNode(1, LLNode(2, LLNode(3)))
        >>> str(b)
        '1 -> 2 -> 3'
        """
        return str(self.item) + (' -> ' + str(self.link) if self.link else '')




def preorder(root: BTNode) -> LLNode:
    """Return the first node in a linked list that contains every value from the
    binary tree rooted at root, listed according to an preorder traversal.

    >>> b = BTNode(1, BTNode(2), BTNode(3))
    >>> repr(preorder(b))
   'LLNode(1, LLNode(2, LLNode(3)))'
   >>> b2 = BTNode(4, BTNode(5))
   >>> b3 = BTNode(7, b, b2)
   >>> str(preorder(b3))
   '7 -> 1 -> 2 -> 3 -> 4 -> 5'
    """

    return _preorder(root)[0]

def _preorder(root: BTNode) -> (LLNode, LLNode):
    """Return the first and last nodes in a linked list that contains every
    value from the binary tree rooted at root, listed according to an preorder
    traversal.
    """

    if not root:
        return None, None

    left_head, left_tail = _preorder(root.left)

    right_head, right_tail = _preorder(root.right)

    # change from right_tail = left_tail to right_tail = left_head
    if not right_tail:
        right_tail = left_head

    if not left_head:
        left_head = right_head

    if left_tail:
        left_tail.link = right_head

    root_node = LLNode(root.item, left_head)

    return root_node, right_tail

我总是得到 '7 -> 1 -> 2' 而不是 '7 -> 1 -> 2 -> 3 -> 4 -> 5' 作为预购函数的输出。我不太清楚为什么。有人可以告诉我如何编辑我当前的代码来解决这个问题吗?

【问题讨论】:

    标签: python-3.x recursion linked-list binary-tree


    【解决方案1】:

    您没有正确返回列表的尾部。我添加了一些调试工具来跟踪 _preorder 的操作——这是在此处发布之前应该做的事情。调试是一项关键技能。

    indent = ""
    def _preorder(root: BTNode) -> (LLNode, LLNode):
        """Return the first and last nodes in a linked list that contains every
        value from the binary tree rooted at root, listed according to an preorder
        traversal.
        """
        global indent
        print(indent, "  ENTER", root.item if root else "NULL")
    
        if not root:
            return None, None
    
        indent += "  "
        left_head, left_tail = _preorder(root.left)
        print (indent, root.item, "Left ", left_head, left_tail, str(left_head))
        right_head, right_tail = _preorder(root.right)
        print (indent, root.item, "Right", right_head, right_tail, str(right_head))
    
        if not right_tail:
            right_tail = left_tail
    
        if not left_head:
            left_head = right_head
    
        if left_tail:
            left_tail.link = right_head
    
        root_node = LLNode(root.item, left_head)
    
        print (indent, "LEAVE", root.item, right_tail.item if right_tail else "NULL")
        indent = indent[2:]
        return root_node, right_tail
    

    完整遍历的输出如下。您可以看到您从未正确链接到右侧;我将把维修留给学生练习。 :-)

       ENTER 7
         ENTER 1
           ENTER 2
             ENTER NULL
           2 Left  None None None
             ENTER NULL
           2 Right None None None
           LEAVE 2 NULL
         1 Left  2 None 2
           ENTER 3
             ENTER NULL
           3 Left  None None None
             ENTER NULL
           3 Right None None None
           LEAVE 3 NULL
         1 Right 3 None 3
         LEAVE 1 NULL
       7 Left  1 -> 2 None 1 -> 2
         ENTER 4
           ENTER 5
             ENTER NULL
           5 Left  None None None
             ENTER NULL
           5 Right None None None
           LEAVE 5 NULL
         4 Left  5 None 5
           ENTER NULL
         4 Right None None None
         LEAVE 4 NULL
       7 Right 4 -> 5 None 4 -> 5
       LEAVE 7 NULL
    
    Main: 7 -> 1 -> 2
    

    对 OP 更新的响应

    显然,这解决了您的问题的一部分。现在,让我们看看从节点 1 的左右子树调用返回时会发生什么,并尝试将它们正确链接到线性列表中:

    left_head, left_tail = _preorder(root.left)
    # returns 2, None
    right_head, right_tail = _preorder(root.right)
    # returns 3, None
    
    if not right_tail:
        right_tail = left_head
    # right_tail is now node 2; this isn't correct: node 3 should be in that spot.
    
    if not left_head:
    # left_head is node 2; not an issue now
    
    if left_tail:
    # left_tail is None; not an issue now
    
    return root_node, right_tail
    # You return nodes 1 and 2;
    #   you never linked node 2 to node 3.
    # You need to fix this.
    

    【讨论】:

    • 感谢调试。但是,我不确定代码的哪一部分没有正确链接右侧。我是否需要添加额外的 if 条件或编辑我当前的 if 条件之一?我真的很困惑。
    • 目前,您需要找到适合您的调试技术。例如,在纸上画出你的树。处理调用,一次一个语句,直到正确链接最左边的子树;那是7-> 1-> 2。现在,备份一个级别并通过右子树进行纸质跟踪, 3. 写下变量值并检查代码 实际 的工作方式,找到您得到 None 的位置,但您希望链接到节点 3
    • 我更改了检查是否有右尾的 if 条件。请看修改后的版本。现在我得到 '7 -> 1 -> 2 -> 4 -> 5' 但我不确定为什么不包括 3
    • 我现在明白了。节点 3 永远不会链接到节点 2。当没有右尾时,我是否必须做 left_head.link = right head?
    • 我不确定你的意图逻辑是什么;你没有解释你期望它如何工作。 left_head.link = right_head 将节点 2 直接链接到节点 3;当你尝试时会发生什么?如果节点 2 有孩子会发生什么?是的,这些都是引导性问题。
    【解决方案2】:

    您的 preorder 代码中似乎有一个错误,该代码处理像 LLNode(value, None) 这样的退货。

    具体而言,当您遍历 bc 都没有子级的 BTNode(a, BTNode(b), BTNode(c)) 时,您不会正确合并。你会想再看看你对这个案例的逻辑。

    【讨论】:

      猜你喜欢
      • 2017-09-16
      • 2012-12-26
      • 2012-01-01
      • 2022-11-11
      • 1970-01-01
      • 1970-01-01
      • 2021-11-20
      相关资源
      最近更新 更多