C 树的根节点处的迭代后序遍历中断
我实现了一个迭代打印二叉树的后序遍历的算法。整个算法都能工作,只是当它到达树的根时,它会进入无限循环 谁能给我指出正确的方向吗?这个问题我已经解决了两天了C 树的根节点处的迭代后序遍历中断,c,algorithm,data-structures,binary-tree,postorder,C,Algorithm,Data Structures,Binary Tree,Postorder,我实现了一个迭代打印二叉树的后序遍历的算法。整个算法都能工作,只是当它到达树的根时,它会进入无限循环 谁能给我指出正确的方向吗?这个问题我已经解决了两天了 void postorder_nonrec_2(treenode *root) { stack_t *s; stack_init(&s, 100); treenode *temp = root; while(1) { while(root) {
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;
}
}
}
也许对于您正在使用的测试用例,只有根上有一个无限循环,但我认为无限循环也可能发生在树中的其他位置,具体取决于特定的树 我认为问题在于,当右边存在子对象时,不能正确地继续弹出堆栈 考虑一个简单的例子,我们有一个根节点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,根变为null 我们回到循环的顶部。根已为null,因此不会将任何内容推送到堆栈上。堆栈不是空的。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和一个右子节点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,根变为null 我们回到循环的顶部。根已为null,因此不会将任何内容推送到堆栈上。堆栈不是空的。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
}
}
发布此答案以提供@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;
}
}
}
发布此答案以提供@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;
}
}
}
如果您唯一的终止子句是“is_empty”,那么请显示“is_empty”的作用,否则我们无法判断……否则,该构造将无限循环。此外,我们还需要验证树的格式是否正确。格式错误的树可能会导致正确的算法永久循环。
stack\u isEmpty(stack*s)
如果堆栈为空,则返回true。这一点似乎很明显,但是,如果堆栈是问题所在呢