# 前中序建立二元樹 >有一個包含N個節點的二元樹,其中有節點1~N(數字不會重複),給定前序和中序走訪的結果,請求出這棵二元樹後序走訪的結果。 ## 唯一性證明 首先我們先證明,給定一棵二元樹的前序與中序走訪,可以決定出唯一的二元樹 整個證明是利用數學歸納法來進行證明,架構如下: >當N=1時,命題顯然成立。 >設N<=k時命題成立。 >證明N=k+1時命題成立。 由於N=1時命題顯然成立,我們僅需證明在N<=k命題成立時,N=k+1也會成立即可。證明如下: 假設二元樹的前序序列為$\{a_1,a_2,a_3,...,a_N\}$,中序序列為$\{b_1,b_2,b_3,...,b_N\}$ 令與$a_1$相同的元素為$b_j$,則可以分為以下三種情況: 1. j=1 根據中序走訪的定義,此時根節點沒有左子樹,$\{a_2,a_3,...,a_N\}$與$\{b_2,b_3,...,b_N\}$(N-1個節點)決定唯一的右子樹。 2. j=N 根據中序走訪的定義,此時根節點沒有右子樹。$\{a_2,a_3,...,a_N\}$與$\{b_1,b_2,...,b_{N-1}\}$(N-1個節點)決定唯一的左子樹 3. 2<=j<=N-1 根據中序走訪的定義,此時左子樹與右子樹的前、中序序列分別為: $\{a_2,a_3,...,a_j\}$,$\{b_1,b_2,...,b_{j-1}\}$與 $\{a_{j+1},a_{j+2},...,a_N\}$,$\{b_{j+1},b_{j+2},...,b_N\}$ 這兩者都是大小<N的子樹,故也會決定唯一的左子樹和右子樹 已知左子樹和右子樹唯一,根節點也已被決定,故得證其唯一性。 ## 演算法 前中序求後序的重點在利用前序來求得樹根,再以中序來分開左右子樹,再遞迴求解即可。 程式碼如下: ```cpp= #include<iostream> #include<vector> using namespace std; void dac(vector<int> in,vector<int> pre){ if(in.size()==0)return; if(in.size()==1){ cout<<in[0]<<" "; return; } int root = pre[0]; int rootIndexInin;//求根在中序的index for(int i = 0;i<in.size();i++){ if(in[i]==root){ rootIndexInin= i; break; } } vector<int> inL,inR,preL,preR; //分開左右子樹的中序序列 for(int i = 0;i<rootIndexInin;i++){ inL.push_back(in[i]); } for(int i = rootIndexInin+1;i<in.size();i++){ inR.push_back(in[i]); } //分開左右子樹的前序序列 for(int i = 1;i<inL.size()+1;i++){ preL.push_back(pre[i]); } for(int i =inL.size()+1;i<pre.size();i++){ preR.push_back(pre[i]); } dac(inL,preL); dac(inR,preR); cout<<root<<" "; } int main(){ int n; cin>>n; vector<int> in,pre; in.resize(n); pre.resize(n); for(int &i:pre)cin>>i; for(int &i:in)cin>>i; dac(in,pre); } ``` 若是要改為建出二元樹,只要將輸出根的編號改為將左右子樹接到該根後,回傳根節點即可。 ## 參考資料 https://blog.csdn.net/qq_34070321/article/details/84583830 HGOJ