三種二叉樹遍歷的非遞歸算法


本文章參考了:https://blog.csdn.net/zhangxiangdavaid/article/details/37115355 的總結;相對原文,力求更加簡要的對三種二叉樹遍歷的非遞歸算法進行歸納

一、二叉樹中序遍歷的非遞歸算法  - LNR

  既然是非遞歸算法,我們自然要借助棧。那么關鍵就是確定什么時候進行入棧,訪問、出棧這幾個動作。

  整個中序遞歸遍歷的思路理解起來並不難,他和我們手動用 LNR 寫出中序遍歷的思路很相近:

     入棧:結點非空時,結點進棧,往左走;

     訪問:棧非空,每出棧一個結點便訪問並往右走;

  

 

 

   當每次向左走到空葉結點時,有上圖兩種情況;但當我們使用空葉子結點時,左邊情況是右邊情況的一種,兩者可以統一處理,即:

  

 

 

   所以中序遍歷的非遞歸代碼很簡潔:

//中序遍歷
void InOrderWithoutRecursion2(BTNode* root)
{
    //空樹
    if (root == NULL)
        return;
    //樹非空
    BTNode* p = root;
    stack<BTNode*> s;
    while (!s.empty() || p)
    {
        if (p)
        {
            s.push(p);
            p = p->lchild;
        }
        else
        {
            p = s.top();
            s.pop();
            cout << setw(4) << p->data; //打印在出棧時
            p = p->rchild;
        }
    }

 

二、二叉樹先序遍歷的非遞歸算法  - NLR

  理解了一之后,再來看先序的非遞歸算法就很好理解了。兩者的區別,只是打印位置的提前,我們腦海中對一棵二叉樹的搜索過程是一樣的。直接給上代碼:

//前序遍歷
void PreOrderWithoutRecursion2(BTNode* root)
{
    if (root == NULL)
        return;
    BTNode* p = root;
    stack<BTNode*> s;
    while (!s.empty() || p)
    {
        if (p)
        {
            cout << setw(4) << p->data;//打印在向左搜尋時
            s.push(p);
            p = p->lchild;
        }
        else
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
    cout << endl;

三、二叉樹后續遍歷非遞歸算法 LRN

  非遞歸后續遍歷算法是3者中最難的,但實際上還是一樣,重在理解:入棧,訪問、出棧的操作規律

  關鍵是理解:訪問一個結點發生在,該節點無右孩子 或者 有右孩子但右孩子剛剛訪問

  代碼的邏輯如下:

 

  代碼:(來自https://www.cnblogs.com/Dawn-bin/p/9844442.html )

  flag = 1表示是一路從左遍歷至空節點;

 1 Status PostOrderTraverse(BiTree T){
 2     BiTree p = T, S[100], pre;
 3     int top = 0, flag = 1;
 4     if(p)
 5         do{
 6             while(p){
 7                 S[top++] = p;
 8                 p = p->lchild;
 9             }
10             // p所有左節點入棧 
11             flag = 1;
12 
13             while(top != 0 && flag == 1){
14                 p = S[top-1];
15                 if(p->rchild == pre || p->rchild == NULL){
16                 //右孩子不存在或右孩子已訪問
17                     top--;
18                     printf("%c ", p->data);
19                     pre = p;
20                     //指向被訪問節點
21                 }
22                 else{
23                     //繼續遍歷右子樹
24                     p = p->rchild;
25                     flag = 0;
26                 }
27             }
28         }while(top != 0);
29     return OK;
30 }//PostOrderTraverse      

  該算法的特點是,棧中所保存的是出棧結點至根的所有祖先結點,利用這點后續非遞歸遍歷有很多應該,比如:

  (1).輸出某個葉子結點的所有祖先

  (2).輸出根結點到所有葉子結點的路徑

  (3).如果二叉樹結點的值是數值,那么求每條路徑上值之和

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM