【问题标题】:Can I do inorder traversal of a binary tree without recursion and stack?我可以在没有递归和堆栈的情况下对二叉树进行顺序遍历吗?
【发布时间】:2023-03-19 02:55:01
【问题描述】:

谁能给我一个解决方案,在不使用递归和不使用堆栈的情况下按顺序遍历二叉树?

【问题讨论】:

标签: tree tree-traversal


【解决方案1】:

第二次编辑:我认为这是正确的。除了通常的 node.left_child 和 node.right_child 之外,还需要 node.isRoot、node.isLeftChild 和 node.parent。

state = "from_parent"
current_node = root
while (!done)
  switch (state)
    case "from_parent":
      if current_node.left_child.exists
        current_node = current_node.left_child
        state = "from_parent"
      else
        state = "return_from_left_child"
    case "return_from_left_child"
      if current_node.right_child.exists
        current_node = current_node.right_child
        state = "from_parent"
      else
        state = "return_from_right_child"
    case "return_from_right_child"
      if current_node.isRoot
        done = true
      else
        if current_node.isLeftChild
         state = "return_from_left_child"
        else
         state = "return_from_right_child"
        current_node = current_node.parent

【讨论】:

  • 我相当肯定这会对深度 > 2 的树产生问题。
  • 你打败了我。但请注意,这仅在字段 node.parent 存在时才有效,即节点知道其父节点。根据二叉树的定义,这是允许的,但不是必需的。
  • 如果你有node.parent,你就不需要node.isRoot。另外,我认为你可以不用 node.isLeftChild。
  • @mbeckish 难以置信,尤其是如果这来自你的头顶
【解决方案2】:

1。双线程树

如果你的树节点有父引用/指针,那么在遍历过程中跟踪你来自哪个节点,这样你就可以决定下一步去哪里。

在 Python 中:

class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right
        self.parent = None
        if self.left:
            self.left.parent = self
        if self.right:
            self.right.parent = self

    def inorder(self):
        cur = self
        pre = None
        nex = None
        while cur:
            if cur.right and pre == cur.right:
                nex = cur.parent
            elif not cur.left or pre == cur.left:
                yield cur.value  # visit!
                nex = cur.right or cur.parent
            else:
                nex = cur.left
            pre = cur
            cur = nex

root = Node(1,
            Node(2, Node(4), Node(5)),
            Node(3)
        )

print([value for value in root.inorder()])  # [4, 2, 5, 1, 3]

2。单线程树

如果您的树节点没有父引用/指针,那么您可以执行所谓的 Morris 遍历,它会临时改变树,使没有右子节点的节点的 right 属性 --暂时指向它的中序后继节点:

在 Python 中:

class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

    def inorder(self):
        cur = self
        while cur:
            if cur.left:
                pre = cur.left
                while pre.right:
                    if pre.right is cur:
                        # We detect our mutation. So we finished
                        # the left subtree traversal.
                        pre.right = None
                        break
                    pre = pre.right
                else:  # prev.right is None
                    # Mutate this node, so it links to curr
                    pre.right = cur
                    cur = cur.left
                    continue
            yield cur.value
            cur = cur.right

root = Node(1,
            Node(2, Node(4), Node(5)),
            Node(3)
        )

print([value for value in root.inorder()])

【讨论】:

    【解决方案3】:

    由于遍历 binary tree 需要某种状态(访问后继节点后返回的节点),这可以由递归隐含的堆栈提供(或由数组显式提供)。

    答案是否定的,你不能。 (根据经典定义)

    最接近以迭代方式遍历二叉树的方法可能是使用heap

    编辑: 或者如已经显示的 threaded binary tree

    【讨论】:

      【解决方案4】:

      是的,你可以。为了做到这一点,你需要一个父指针来提升树。

      【讨论】:

        【解决方案5】:

        从 tree_first() 开始,继续 tree_next() 直到获得 NULL。 完整代码:https://github.com/virtan/tree_closest

        struct node {
            int value;
            node *left;
            node *right;
            node *parent;
        };
        
        node *tree_first(node *root) {
            while(root && root->left)
                root = root->left;
            return root;
        }
        
        node *tree_next(node *p) {
            if(p->right)
                return tree_first(p->right);
            while(p->parent) {
                if(!p->parent->right || p->parent->right != p)
                    return p->parent;
                else p = p->parent;
            }
            return 0;
        }
        

        【讨论】:

          【解决方案6】:

          正如这里有人已经说过的,这是可能的,但不能没有父指针。如果需要,父指针基本上允许您遍历“路径”,因此可以打印出节点。 但是为什么递归在没有父指针的情况下工作?好吧,如果您了解递归,它会是这样的(想象一下递归堆栈):

            recursion //going into
             recursion
              recursion
               recursion 
               recursion //going back up
              recursion
             recursion
            recursion
          

          因此,当递归结束时,您以相反的顺序打印了二叉树的选定侧。

          【讨论】:

          • OP 确实明确要求涉及递归的东西。
          猜你喜欢
          • 2021-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-08
          • 2012-05-10
          • 2018-06-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多