简体   繁体   English

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

[英]Iterative postorder traversal breaks at root node of tree

I implemented an algorithm for printing the postorder traversal of a binary tree iteratively. 我实现了一种算法,用于迭代地打印二叉树的后序遍历。 The entire algorithm works, except it goes in infinite loop when it hits the root of tree. 整个算法都起作用,除了当它到达树的根部时会进入无限循环。

Can somebody point me in right direction? 有人可以指出我正确的方向吗? I've been stuck on this problem for 2 days now. 我已经在这个问题上停留了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;
        }

    }
}

Perhaps with the test cases you are using, there is an infinite loop at only the root, but I think the infinite loop could also occur at other places in the tree, depending on the specific tree. 也许在您使用的测试用例中,仅在根部存在一个无限循环,但是我认为该无限循环也可能发生在树的其他位置,具体取决于特定的树。

The problem, I think, is that you do not correctly continue to pop up the stack when children exist on the right. 我认为问题是,当右侧有子级时,您不会正确继续弹出堆栈。

Consider the simple example where we have a root node 1 with a left child 0 and a right child 2, and suppose that 2 has a right child named 3. 考虑一个简单的示例,其中我们的根节点1的左子节点为0,右子节点为2,并假设2的右节点为3。

In the first loop we push 1 and 0 onto the stack. 在第一个循环中,我们将1和0压入堆栈。 Then 0 has no left child, so root becomes null. 然后0没有左子节点,因此root变为null。 The stack is not empty, so we continue. 堆栈不为空,因此我们继续。 0 is at the top of the stack and has no right child, so we enter the first branch of the if statement. 0在堆栈的顶部,并且没有合适的子级,因此我们输入if语句的第一个分支。 We then print out 0 and because 0 is the left child of 1 -- 1 is now the top of the stack -- the root becomes 2. 然后我们打印出0,因为0是1的左孩子-1现在是堆栈的顶部-根变成2。

At this point we return to the top. 至此,我们回到顶部。 2 is the root and gets pushed onto the stack. 2是根,并被压入堆栈。 2 has no left child, so the root becomes null. 2没有左子节点,因此根变为空。 The stack is not empty. 堆栈不为空。 2 is at the top of the stack. 2在堆栈的顶部。 It has a right child, so we enter the second branch of the if statement. 它有一个正确的孩子,因此我们进入if语句的第二个分支。 This makes 3 the root. 这使3成为根。

We return to the top of the outer loop. 我们回到外循环的顶部。 3 is the root and gets pushed onto the stack. 3是根,并被压入堆栈。 3 has no left child, so the root becomes null. 3没有左子节点,因此根变为空。 The stack is not empty. 堆栈不为空。 3 has no right child, so we enter the first branch of the if statement. 3没有合适的孩子,因此我们进入if语句的第一个分支。 We print out 3. Then because 3 is the right child of 2 -- 2 is at the top of the stack now -- we pop 2 off the stack, print out 2, and the root becomes null. 我们打印出3。然后因为3是2的正确子级-2现在位于堆栈的顶部-我们将2弹出堆栈,打印出2,并且根变为空。

We return to the top of the loop. 我们回到循环的顶部。 The root is already null, so nothing is pushed onto the stack. 根已经为空,因此没有任何内容被压入堆栈。 The stack is not empty. 堆栈不为空。 1 is at the top of the stack. 1在堆栈的顶部。 At this point the proper thing to do is to pop 1 from the stack because we have already processed its right child; 此时,正确的做法是从堆栈中弹出1,因为我们已经处理了它的正确子级; however, 1 is at the top of the stack and does have a right child, so we enter the second branch of the if statement and 2 becomes the root. 但是,1在堆栈的顶部,并且确实有一个正确的子代,因此我们进入if语句的第二个分支,而2成为根。 The situation is exactly the same as it was at the two paragraphs ago, with 1 the only element on the stack and 2 the root, so we get an infinite loop back to there. 这种情况与前两段中的情况完全相同,其中1是堆栈上的唯一元素,而2是根,因此我们回到了无限循环。

If we changed the example so that 3 also has a right child named 4, then, if I read correctly, we would never print out 2 and would loop printing out 4 and 3. 如果我们更改示例,使3也有一个名为4的正确子元素,那么,如果我没看错,我们将永远不会打印出2并循环打印出4和3。

To correct the problem, you should continue to pop the stack as long as the element you are processing is the right child of the top of the stack. 要解决此问题,只要要处理的元素是堆栈顶部的右子元素,就应该继续弹出堆栈。 I haven't compiled or tested this, but I think it would work to write something like 我尚未对此进行编译或测试,但是我认为编写类似

    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
        }
    }

Posting this answer to provide the full code of the solution suggested by @Evan VanderZee 发布此答案以提供@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