null
是否可以在不使用visited
标志或 a 的情况下对其节点具有父指针(根的父指针)的 BST 进行迭代顺序遍历stack
?
我用谷歌搜索并没有找到回复。关键是,我怎么知道——在某个节点——我刚刚到达它,而我已经完成了它下面的所有事情?
null
是否可以在不使用visited
标志或 a 的情况下对其节点具有父指针(根的父指针)的 BST 进行迭代顺序遍历stack
?
我用谷歌搜索并没有找到回复。关键是,我怎么知道——在某个节点——我刚刚到达它,而我已经完成了它下面的所有事情?
您可以这样做,您只需要记住上次访问的节点以及当前节点即可。问题陈述不允许这样做:visited
每个节点上的标志和 astack
都是(最坏情况)O(n),记住最后一个节点只是O(1)。
在 C# 中,算法可能如下所示:
static void Walk(Node node)
{
Node lastNode = null;
while (node != null)
{
if (lastNode == node.Parent)
{
if (node.Left != null)
{
lastNode = node;
node = node.Left;
continue;
}
else
lastNode = null;
}
if (lastNode == node.Left)
{
Output(node);
if (node.Right != null)
{
lastNode = node;
node = node.Right;
continue;
}
else
lastNode = null;
}
if (lastNode == node.Right)
{
lastNode = node;
node = node.Parent;
}
}
}
这是另一种方法。我认为它本质上等同于 svick 的答案,但避免了额外的变量。这个版本是用 Python 实现的:
node=root
if node is not None:
while node.left is not None:
node=node.left
while node is not None:
output(node)
if node.right is not None:
node=node.right
while node.left is not None:
node=node.left
else:
while node.parent is not None and node.parent.right is node:
node=node.parent
node=node.parent
您最后访问的任何节点都决定了您需要访问的下一个节点。如果您刚刚访问过节点 X,那么您需要访问 X 右侧的最左侧节点。如果 X 没有右孩子,则下一个节点是节点 X 不是来自右侧的第一个祖先边。
使用svick的正确想法(见他的回答),这是C++ 中经过测试的代码。请注意,我没有测试他的代码,甚至没有看它,我只是采纳了他的想法并实现了我自己的功能。
void in_order_traversal_iterative_with_parent(node* root) {
node* current = root;
node* previous = NULL;
while (current) {
if (previous == current->parent) { // Traversing down the tree.
previous = current;
if (current->left) {
current = current->left;
} else {
cout << ' ' << current->data;
if (current->right)
current = current->right;
else
current = current->parent;
}
} else if (previous == current->left) { // Traversing up the tree from the left.
previous = current;
cout << ' ' << current->data;
if (current->right)
current = current->right;
else
current = current->parent;
} else if (previous == current->right) { // Traversing up the tree from the right.
previous = current;
current = current->parent;
}
}
cout << endl;
}
public void inorderNoStack() {
if (root == null) {
return;
}
// use the previous to always track the last visited node
// helps in deciding if we are going down/up
Node prev = null;
Node curr = root;
while (curr != null) {
// going down
if (prev == null || prev.left == curr || prev.right == curr) {
if (curr.left != null) {
prev = curr;
curr = curr.left;
continue;
} else {
visitn(curr);
if (curr.right != null) {
prev = curr;
curr = curr.right;
continue;
} else {
// swap states
prev = curr;
curr = prev.parent;
}
}
}
// going up after left traversal
if (curr != null && prev == curr.left) {
visitn(curr);
if (curr.right != null) {
prev = curr;
curr = curr.right;
continue;
} else {
// swap states
prev = curr;
curr = prev.parent;
}
}
// going up after right traversal
if (curr != null && prev == curr.right) {
// swap states
prev = curr;
curr = prev.parent;
}
}
}
第 1 步:编写一个返回有序后继的函数
步骤2:从最左边的节点开始,找到有序的后继,直到没有
public class TreeNode {
int data;
TreeNode left;
TreeNode right;
TreeNode parent;
}
public class TreeUtility {
public void inorderNoRecursion(TreeNode root) {
TreeNode current = leftmostNode(root);
while(current != null) {
System.out.println(current.data);
current = inorderSuccessor(current);
}
}
public TreeNode inorderSuccessor(TreeNode node) {
if (node.right!=null) {
return leftmostNode(node.right);
}
TreeNode p = node.parent;
TreeNode c = node;
while(p!=null && c != p.left) {
c = p;
p = p.parent;
}
return p;
}
private TreeNode leftmostNode(TreeNode node) {
while (node.left != null) {
node = node.left;
}
return node;
}
}
我的 Java 解决方案没有在现有树上引入任何标志。也没有父指针。这种方法将使节点保持在树的高度。请看一看。
https://github.com/skanagavelu/Algorithams/blob/master/src/tree/InOrderTraversalIterative.java
关键是父指针(或改变树的能力),但您需要恒定数量的额外状态(例如,以下协程的程序计数器)。
这是在 C++ 中:
void InOrder(Node *r)
{
if(r==NULL)
return;
Node *t=r;
while(t!=NULL)
t=t->left;
while(t!=r)
{
if(t==(t->parent->left))
{
cout<<t->parent->data;
t=t->parent->right;
if(t!=NULL)
{
while(t!=NULL)
t=t->left;
}
if(t==NULL)
t=t->parent;
}
if(t==t->parent->right)
{
t=t->parent;
}
}
}