二叉樹的非遞歸遍歷與層次遍歷


二叉樹的遞歸遍歷很好寫,也很好理解。但因為是遞歸程序,不可避免地需要調用系統棧,耗時較長,這里我們來探究一下二叉樹的非遞歸遍歷的算法。這種方法需要使用棧這種數據結構,這里關於棧的一些操作函數可以看成偽代碼吧,先給出線序、中序、后序遍歷的代碼即說明。

 

先序遍歷:

 1 void PreOrderTraverse(BinTree b)
 2 {
 3     InitStack(S);///初始化創建棧
 4     BinTree p=b;///p為工作指針
 5     while(p||!isEmpty(s))
 6     {
 7         while(p)///到最左下的孩子
 8         {
 9             printf(" %c ",p->date);///先序先遍歷結點
10             Push(S,p);///入棧
11             p=p->lchild;
12         }
13         if(!isEmpty(s))///在棧不為空的情況下,左孩子為空,彈出該結點,遍歷右孩子
14         {
15             p=Pop(s);
16             p=p->rchild;
17         }
18     }
19 }

 再給出使用數組模擬的函數

 1 void Preorder_n(BiTree bt)  /*先序遍歷的非遞歸算法*/
 2 {
 3     BiTree stack[MAX],p;
 4     int top=0,i;
 5     for(i=0; i<MAX; i++)
 6     {
 7         stack[i]=NULL; /*初始化棧*/
 8     }
 9     p=bt;
10     do
11     {
12         while(p)
13         {
14              printf("%c",p->data);
15              stack[top++]=p;
16              p=p->lchild;
17         }
18         if(top!=0)
19         {
20             p=stack[top-1];//去棧底
21             top--;//出棧
22             p=p->rchild;
23         }
24     }while(top!=0||p!=NULL);
25 }
View Code

 

 

中序遍歷:

void InOrderTraverse(BinTree b)
{
    InitStack(S);///初始化創建棧
    BinTree p=b;///p為工作指針
    while(p||!isEmpty(s))
    {
        while(p)
        {
            Push(S,p);///中序現將結點進棧保存
            p=p->lchild;
        }///遍歷到左下角盡頭再出棧訪問
        if(!isEmpty(s))///在棧不為空的情況下,左孩子為空,彈出該結點,遍歷右孩子
        {
            p=Pop(s);
            printf(" %c ",p->data);
            p=p->rchild;///遍歷右孩子
        }
    }
}

 

 再給出使用數組模擬的函數

 1 void InOrder_n(BiTree bt)  /*中序遍歷的非遞歸算法*/
 2 {
 3     BiTree stack[MAX],p;
 4     int top=0,i;
 5     for(i=0; i<MAX; i++)
 6     {
 7         stack[i]=NULL; /*初始化棧*/
 8     }
 9     p=bt;
10     do
11     {
12         while(p)//順着左鏈走到盡頭
13         {
14             stack[top++]=p;
15             p=p->lchild;
16         }
17         if(top>0)
18         {
19             p=stack[top-1];
20             printf("%c",stack[top-1]->data);
21             top--;
22             p=p->rchild;
23         }
24     }while(top!=0||p);
25 }
View Code

 


后序遍歷:后序遍歷較前兩種遍歷方法比較難實現,原因在於需要遍歷完左子樹,遍歷完右子樹,最后才去訪問根節點。這樣棧頂結點可能會從他的左子樹返回,也有可能從他的右子樹返回,需要區分這種情況,如果是第一次從左子樹返回,那么還需要去遍歷其右子樹,如果是從右子樹返回,那么直接返回該結點就可以了。這里使用輔助指針來區分來源。

void PostOrderTraverse(BinTree b)
{
    InitStack(S);///初始化創建棧
    BinTree p=b, r=NULL;///p為工作指針,輔助指針r
    while(p||!isEmpty(s))
    {
        if(p)///從根節點到最左下角的左子樹都入棧
        {
            Push(S,p);///中序現將結點進棧保存
            p=p->lchild;
        }
        else
        {
            GetTop(S,p);///取棧頂,注意!不是出棧!
            if(p->rchild&&p->rchild!=r)///1.右子樹還沒有訪問並且右子樹不空,第一次棧頂
            {
                p=p->rchild;///進入右子樹
            }
            else///右子樹已經訪問或為空,接下來出棧訪問結點,第二次棧頂
            {
                p=Pop(s);
                printf(" %c ",p->data);
                r=p;///指向訪問過的右子樹結點
                p=NULL;///使p為空繼續訪問棧頂
            }
        }
    }
}

 數組模擬:

 1 void PostOrder_n(BiTree bt)
 2 {
 3     BiTree stack[MAX],p,r;
 4     int top=0,i;
 5     for(i=0; i<MAX; i++)
 6     {
 7         stack[i]=NULL; /*初始化棧*/
 8     }
 9     p=bt, r=NULL;///p為工作指針,輔助指針r
10     do
11     {
12         if(p)///從根節點到最左下角的左子樹都入棧
13         {
14             stack[top++]=p;///中序現將結點進棧保存
15             p=p->lchild;
16         }
17         else
18         {
19             p=stack[top-1];///取棧頂,注意!不是出棧!
20             if(p->rchild&&p->rchild!=r)///1.右子樹還沒有訪問並且右子樹不空,第一次棧頂
21             {
22                 p=p->rchild;///進入右子樹
23             }
24             else///右子樹已經訪問或為空,接下來出棧訪問結點,第二次棧頂
25             {
26                 top--;
27                 printf("%c",p->data);
28                 r=p;///指向訪問過的右子樹結點
29                 p=NULL;///使p為空繼續訪問棧頂
30             }
31         }
32     } while(p||top!=0);
33 }
View Code

 

層次遍歷:

從二叉樹的第一層(根節點)開始,從上至下逐層遍歷,在每一層中又按照從左到右的順序對結點逐個遍歷。我們可以看出如果某個結點比同一層的先遍歷,其孩子也將比其同層的孩子結點先遍歷,這種先進先出的方式,不就是隊列這種數據結構嗎?

 1 void LevelOrder(BiTree b)
 2 {
 3     InitQueue(Q);///初始化建立隊列
 4     BinTree p;
 5     EnQueue(Q,b);///根節點入隊
 6     while(!isEmpty(Q))///隊列不空循環
 7     {
 8         DeQueue(Q,p);///隊頭元素出隊
 9         printf(" %c ",p->data);
10         ///左右孩子入隊
11         if(p->lchild!=NULL)
12         {
13             EnQueue(Q,p->lchild);
14         }
15         if(p->rchild!=NULL)
16         {
17             EnQueue(Q,p->rchild);
18         }
19     }
20 }

 使用C++ STL庫 queue 的函數:

 1 void LevelOrder(BiTree p)
 2 {
 3     queue<BiTree>Q;//使用C++ STL庫
 4     Q.push(p);//根節點入隊
 5     while(!Q.empty())//隊列不空循環
 6     {
 7         p=Q.front();//取對頭
 8         printf("%c",p->data);//左右孩子入隊
 9         if(p->lchild!=NULL)
10         {
11             Q.push(p->lchild);
12         }
13         if(p->rchild!=NULL)
14         {
15             Q.push(p->rchild);
16         }
17         Q.pop();//隊頭元素出隊
18     }
19     printf("\n");
20 }
View Code

 


免責聲明!

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



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