我实现了一种算法,用于迭代地打印二叉树的后序遍历。整个算法都有效,除非它遇到树根时无限循环。
有人能指出我正确的方向吗?我已经坚持这个问题2天了。
void postorder_nonrec_2(treenode *root)
{
stack_t *s;
stack_init(&s, 100);
treenode *temp = root;
while(1)
{
while(root)
{
push(s, root);
root = root -> left;
}
if(stack_isEmpty(s))
break;
if(!top(s) -> right)
{
root = pop(s);
printf("%d ", root -> data);
if(root == top(s) -> left)
{
root = top(s) -> right;
}
else if(root == top(s) -> right)
{
printf("%d ", pop(s) -> data);
root = NULL;
}
}
else
{
root = top(s) -> right;
}
}
}
答案 0 :(得分:0)
也许对于您正在使用的测试用例,只有根处有一个无限循环,但我认为无限循环也可能出现在树中的其他位置,具体取决于特定的树。
我认为问题是,当孩子存在于右侧时,你没有正确地继续弹出堆栈。
考虑一个简单的例子,我们有一个根节点1,一个左子0和一个右子2,并假设2有一个名为3的右子。
在第一个循环中,我们将1和0推入堆栈。那么0没有左子,所以root变为null。堆栈不是空的,所以我们继续。 0位于堆栈顶部且没有右子项,因此我们输入if语句的第一个分支。然后我们打印出0,因为0是1 - 1的左子,现在是堆栈的顶部 - 根变为2。
此时我们回到顶部。 2是根并被推入堆栈。 2没有左子,因此根变为null。堆栈不是空的。 2位于堆栈的顶部。它有一个正确的孩子,所以我们进入if语句的第二个分支。这使得3成为根。
我们返回到外循环的顶部。 3是根并被推入堆栈。 3没有左子,因此根变为null。堆栈不是空的。 3没有正确的孩子,所以我们输入if语句的第一个分支。我们打印出来3.然后因为3是2 - 2的正确子项现在位于堆栈顶部 - 我们从堆栈中弹出2,打印出2,然后根变为空。
我们回到循环的顶部。根目录已经为空,因此没有任何东西被压入堆栈。堆栈不是空的。 1位于堆栈的顶部。在这一点上,正确的做法是从堆栈中弹出1,因为我们已经处理了它的正确子项;但是,1位于堆栈的顶部,并且确实有一个正确的子节点,因此我们输入if语句的第二个分支,2成为根。情况与两段前的情况完全相同,其中1是堆栈中唯一的元素,2是根,所以我们得到一个无限循环回到那里。
如果我们更改了示例以便3也有一个名为4的右子,那么,如果我正确读取,我们将永远不会打印出2并将循环打印出4和3。
要解决此问题,只要您正在处理的元素是堆栈顶部的正确子元素,您就应该继续弹出堆栈。我没有编译或测试过这个,但我认为编写像
这样的东西会起作用 if (!top(s) -> right)
{
root = pop(s);
printf("%d ", root -> data);
while (!stack_isEmpty(s) && root == top(s) -> right)
{
root = pop(s);
printf("%d ", root -> data);
}
if (!stack_isEmpty(s) && root == top(s) -> left)
{
// checking root == top(s) -> left is probably redundant,
// since the code is structured so that root is either
// a child of top(s) or null if the stack is not empty
root = top(s) -> right;
}
else
{
root = NULL;
// could actually break out of outer loop here, but
// to be more consistent with code in the question
}
}
答案 1 :(得分:0)
发布此答案以提供@Evan VanderZee建议的解决方案的完整代码
void postorder_nonrec_2(treenode *root)
{
stack_t *s;
stack_init(&s, 100);
while(1)
{
while(root)
{
push(s, root);
root = root -> left;
}
if(stack_isEmpty(s))
break;
if (!top(s) -> right)
{
root = pop(s);
printf("%d ", root -> data);
while (!stack_isEmpty(s) && root == top(s) -> right)
{
root = pop(s);
printf("%d ", root -> data);
}
root = NULL;
}
else
{
root = top(s) -> right;
}
}
}