我可以在没有递归和堆栈的情况下对二叉树进行顺序遍历吗?
Posted
技术标签:
【中文标题】我可以在没有递归和堆栈的情况下对二叉树进行顺序遍历吗?【英文标题】:Can I do inorder traversal of a binary tree without recursion and stack? 【发布时间】:2010-04-07 18:41:36 【问题描述】:谁能给我一个解决方案,在不使用递归和不使用堆栈的情况下按顺序遍历二叉树?
【问题讨论】:
如果你能做到,那就不是二叉树 这不是作业吗?在您的情况下,计数器算作堆栈吗? @Jim Lewis 我不知道这个,谢谢en.wikipedia.org/wiki/Threaded_binary_tree 【参考方案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 确实明确要求不涉及递归的东西。以上是关于我可以在没有递归和堆栈的情况下对二叉树进行顺序遍历吗?的主要内容,如果未能解决你的问题,请参考以下文章