1. 程式人生 > >二叉樹的遍歷 &【NOIP2001普及組】& 洛谷 P1030 求先序排列

二叉樹的遍歷 &【NOIP2001普及組】& 洛谷 P1030 求先序排列

題目 輸出 image pre ext bubuko 二叉樹 找到 pan

題目鏈接

https://www.luogu.org/problemnew/show/P1030

模板題

先講一下二叉樹的遍歷

二叉樹的遍歷

  • 分類
  • 性質
  • 求法

分為三類:

  1. 先序遍歷(PreOrder):根節點→左子樹→右子樹
  2. 中序遍歷(InOrder):左子樹→根節點→右子樹
  3. 後序遍歷(PostOrder):左子樹→右子樹→根節點

我們可知:

  • **序遍歷實際上是指根節點的位置
  • 無論哪種遍歷順序,左子樹都在右子樹的前面
  • 在前序遍歷中,第一個點是根節點
  • 在後序遍歷中,最後一個點是根節點

例如這樣一個二叉樹:

技術分享圖片

它的先序遍歷:A--B--D--E--X--C--F--Y--Z

它的中序遍歷:D--B--X--E--A--Y--F--Z--C

它的後序遍歷:D--X--E--B--Y--Z--F--C--A

求後序遍歷

用到遞歸的思想,求整個二叉樹的後序遍歷就是求每個子樹的後序遍歷,最後連接起來即可。

 1 #include<iostream>
 2 using namespace std;
 3 string z,q;
 4 int len,cnt;
 5 void PostOrder(int l,int r){//求中序遍歷中l到r這個子樹的後序遍歷 
 6     if
(l>r) return; //邊界條件 7 int i; 8 char ans=q[cnt++]; //先序遍歷的第一個是根節點 9 for(i=l;i<=r;i++){ 10 if(z[i]==ans) break;//找到根節點在中序遍歷中的位置 11 } 12 PostOrder(l,i-1); //遞歸左子樹 13 PostOrder(i+1,r); //遞歸右子樹 14 cout<<ans; //
註意後序遍歷是左右根的順序,所以最後輸出根 15 } 16 int main() 17 { 18 cin>>z>>q; //z是中序遍歷,q是先序遍歷 19 len=z.length()-1; 20 PostOrder(0,z.length()-1);//一開始是整個子樹 21 return 0; 22 }

求先序遍歷

這比求後序遍歷稍微有些復雜,需要保留根節點,即:PreOrder(左端點,右端點,根節點)。這是因為根節點在先序遍歷中是從前往後排列的,而在後序遍歷中不是這樣的。

還是這個圖:

技術分享圖片

它的先序遍歷:A--B--D--E--X--C--F--Y--Z

它的中序遍歷:D--B--X--E--A--Y--F--Z--C

它的後序遍歷:D--X--E--B--Y--Z--F--C--A

在先序遍歷中,根節點依次是A,B,D,E,X……是按照從前往後的順序排列的,所以可以直接 ans=q[cnt++]; 而在後序遍歷中卻不是這樣。

有人或許會說:那後序遍歷中根節點是從後往前排列的,其實這是一個錯誤的結論。還是看這一個二叉樹,後序遍歷是A,C,F,Z,Y,B……顯然是按照根→右子樹→左子樹排列的,而我們求的先序排列是根→左→右,顯然這種方法不行。

所以我們需要多傳一個參數,來記錄根節點在後序遍歷中的位置。重點:確定子樹的根節點在後序遍歷中的位置。

 1 #include<iostream>
 2 using namespace std;
 3 string z,h;
 4 int len;
 5 void PreOrder(int l,int r,int root){//求中序遍歷中l到r這個子樹(以root為根)的後序遍歷 
 6     if(l>r) return;
 7     int i;
 8     for(i=l;i<=r;i++){                //和求後序遍歷一樣 
 9         if(z[i]==h[root]) break;
10     }
11     cout<<h[root];                 //註意是根左右 
12     PreOrder(l,i-1,root-(r-i)-1);//左子樹的根節點就是原來根節點減去右子樹的節點數的上一個(r-i就是右子樹的節點數) 
13     PreOrder(i+1,r,root-1);         //右子樹的根節點就是後序遍歷中原來根節點的上一個 
14 }
15 int main()
16 {
17     cin>>z>>h;
18     len=h.length()-1;
19     PreOrder(0,z.length()-1,len);
20     return 0;
21 }

而在知道先序遍歷和後序遍歷的情況下,中序遍歷是不唯一的,但可以求出情況數(後面將做補充)。

//NOIP2001普及組t3

二叉樹的遍歷 &【NOIP2001普及組】& 洛谷 P1030 求先序排列