簡體   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