迭代后序遍历在树的根节点中断

Iterative postorder traversal breaks at root node of tree

我实现了一种迭代打印二叉树后序遍历的算法。整个算法都有效,除了它在到达树的根部时进入无限循环。

有人能指出我正确的方向吗?我已经被这个问题困扰了 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;
        }

    }
}

也许你使用的测试用例,只有根部有无限循环,但我认为无限循环也可能发生在树的其他地方,具体取决于具体的树。

问题我觉得是当children存在右边的时候你没有正确的继续弹出栈

考虑一个简单的例子,我们有一个根节点 1,左 child 0 和右 child 2,并假设 2 有一个名为 3 的右 child。

在第一个循环中,我们将 1 和 0 压入堆栈。那么0就没有左child了,所以root就变成了null。堆栈不为空,所以我们继续。 0在栈顶,没有权利child,所以我们进入if语句的第一个分支。然后我们打印出 0,因为 0 是 1 的左边 child——1 现在是栈顶——根变成 2.

至此我们return到了顶部。 2 是根并被压入堆栈。 2 没有左child,所以根变为空。堆栈不为空。 2 在堆栈的顶部。它有一个正确的child,所以我们进入if语句的第二个分支。这使 3 成为根。

我们return到外循环的顶部。 3 是根并被压入堆栈。 3 没有左child,所以根变为空。堆栈不为空。 3没有权利child,所以我们进入if语句的第一个分支。我们打印出 3。然后因为 3 是 2 的右边 child -- 2 现在在堆栈的顶部 -- 我们将 2 弹出堆栈,打印出 2,并且根变为空。

我们return到循环的顶部。根已经为空,因此没有任何内容被压入堆栈。堆栈不为空。 1 在堆栈的顶部。此时正确的做法是从堆栈中弹出 1,因为我们已经处理了它的右边 child;然而,1 在堆栈的顶部并且确实有一个右 child,因此我们进入 if 语句的第二个分支并且 2 成为根。情况和前两段完全一样,1是栈上唯一的元素,2是根,所以我们得到一个无限循环回到那里。

如果我们更改示例,使 3 也有一个名为 4 的权利 child,那么,如果我没看错的话,我们将永远不会打印出 2,而是会循环打印出 4 和 3。

要更正此问题,只要您正在处理的元素位于堆栈顶部的右侧 child,您就应该继续弹出堆栈。我还没有编译或测试过这个,但我认为写一些像

这样的东西会奏效
    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;
        }
    }
}