目錄
-
需要用到的概念
- 有根二叉樹:如果一根樹擁有一個根結點,且所有結點的子結點數都不超過2,那麼這棵樹稱爲有根二叉樹。
- 樹的遍歷:
- 前序遍歷(Preorder Tree Walk) :按照根結點、左子樹、右子樹的順序輸出結點編號。
- 中序遍歷(Inorder Tree Walk):按照左子樹、根結點、右子樹的順序輸出結點編號。
- 後序遍歷(PostOrder Tree Walk):按照左子樹、右子樹、根結點的順序輸出結點編號。
- (可以發現左子樹、右子樹的先後順序沒有改變,而根結點的位置對應了“前”“中”“後”三個位置)
-
題目描述
-
樹的重建(Reconstruction of the tree)
-
現有兩個結點序列,分別是對同一個二叉樹進行前序遍歷和中序遍歷的結果。請編寫一個程序,輸出該二叉樹按後序遍歷時的結果。
-
輸入
-
第1行輸入二叉樹的結點數n。
-
第2行輸入前序遍歷的結點編號序列,相鄰編號用空格隔開。
-
第3行輸入中序遍歷的結點編號序列,相鄰編號用空格隔開。
-
結點編號爲從1至n的整數。請注意,1不一定是根結點。
-
-
輸出
-
在1行中輸出按後序遍歷時的結點編號序列。相鄰結點編號之間用1個空格隔開。
-
-
限制
-
1≤結點數≤100
-
-
-
解題思路
- 輸出未知二叉樹的後序遍歷
- 這個問題可以變形爲:
- 輸出當前二叉樹左子樹的後序遍歷;
- 輸出當前二叉樹右子樹的後序遍歷;
- 輸出當前二叉樹的根結點。
- 根據已知的前序遍歷和後序遍歷,我們可以知道:
- 當前二叉樹的根結點 -> 二叉樹的前序遍歷的首元素;
- 當前二叉樹的左右子樹 -> 二叉樹的中序遍歷的位於根結點左右兩邊的元素集合。
- 找到根結點的過程我們可以通過前序遍歷的特性O(1)的查詢。
- 對於尋找左右子樹的過程,我們也可以通過預處理O(1)的查詢。
- 預處理:將中序遍歷中的元素下標記錄下來,排序後便可以O(1)的查詢了。
-
代碼實現
-
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int size = 150; int n,Preorder[size],Inorder[size]; struct data { int k,i; data() { } data(int a,int b) { k = a; i = b; }//結構體的構造函數 } temp[size]; bool cmp(data a,data b) { return a.k < b.k; }//結構體的比較函數 void make_Postorder(int l1,int r1,int l2,int r2) { if(l1 == r1) cout << Preorder[l1] << ' ';//遞歸出口:如果到達葉結點則退出 else { int root = Preorder[l1]; int divide = temp[root].i;//記錄此子樹中根在中序遍歷中的位置 int size1 = divide - l2;//記錄此子樹中左子樹的結點個數 make_Postorder(l1 + 1,l1 + size1,l2,divide - 1); make_Postorder(l1 + size1 + 1,r1,divide + 1,r2); cout << root << ' '; } return; } int main() { memset(Preorder,0,sizeof(Preorder));//初始化 memset(Inorder,0,sizeof(Inorder)); cin >> n; for(int i = 1;i <= n;i++) cin >> Preorder[i]; for(int i = 1;i <= n;i++) { cin >> Inorder[i]; temp[i] = data(Inorder[i],i); } sort(temp + 1,temp + 1 + n,cmp); make_Postorder(1,n,1,n); return 0; }