繁体   English   中英

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

[英]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;
        }

    }
}

也许在您使用的测试用例中,仅在根部存在一个无限循环,但是我认为该无限循环也可能发生在树的其他位置,具体取决于特定的树。

我认为问题是,当右侧有子级时,您不会正确继续弹出堆栈。

考虑一个简单的示例,其中我们的根节点1的左子节点为0,右子节点为2,并假设2的右节点为3。

在第一个循环中,我们将1和0压入堆栈。 然后0没有左子节点,因此root变为null。 堆栈不为空,因此我们继续。 0在堆栈的顶部,并且没有合适的子级,因此我们输入if语句的第一个分支。 然后我们打印出0,因为0是1的左孩子-1现在是堆栈的顶部-根变成2。

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

我们回到外循环的顶部。 3是根,并被压入堆栈。 3没有左子节点,因此根变为空。 堆栈不为空。 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
        }
    }

发布此答案以提供@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;
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM