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

时间:2015-09-24 17:41:06

标签: c algorithm data-structures binary-tree postorder

我实现了一种算法,用于迭代地打印二叉树的后序遍历。整个算法都有效,除非它遇到树根时无限循环。

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

    }
}

2 个答案:

答案 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;
        }
    }
}