二叉樹的遍歷及例題
前序遍歷就是根在前,中序是根在根在中,
前序遍歷
根 --> 左 --> 右
中序遍歷
左 --> 根 --> 右
后序遍歷
左 --> 右 --> 根
如圖是一顆二叉樹
前序(根左右),中序(左根右),后序(左右根)
它的前序遍歷結果為: A B D F G H I E C 代表的含義為A( B ( D ( F ,G( H ,I ) ) ,E ) , C )
所以第一個點一定是根節點
它的中序遍歷結果為: F D H G I B E A C
它代表的含義,A(已知它不是葉子節點)在中間說明A的左邊是左兒子,A的右邊是他的右兒子
它的后序遍歷結果為:F H I G D E B C A
解題:
如果有前序和中序或者中序和后序可以得到二叉樹,從而得到后序。
如果有前序和后序無法的得到二叉樹。
1.已知前序、中序遍歷求后序遍歷
例:
前序遍歷:A B G D E C F H
中序遍歷:G B E D A F C H
構建二叉樹的步驟:
1.根據前序遍歷特點,得到根節點A
2.觀察中序遍歷結果: 根節點左邊節點為G B E D,根節點的右邊節點為 F C H。同時,兩段也是左右子樹的中序遍歷的結果。
B G D E也是左子樹前序遍歷的結果。 C F H也是右子樹前序遍歷的結果。
3.重復 1 2的步驟,直到找到葉子結點就可以得到最后的二叉樹。
例題:
https://vjudge.net/contest/407936#problem/K
題意:給出中序遍歷和前序遍歷,讓你找到后序遍歷的結果。
#include <iostream>
using namespace std;
const int maxn = 105;
int pre[maxn],in[maxn],pos[maxn];
int infind(int root,int l,int r){//在中序遍歷中找到當前根節點的位置
for(int i=l;i<r;i++){
if(in[i]==root){
return i;
}
}
}
int cnt;
void posorder(int prel,int prer,int inl,int inr){
if(prel==prer) return ;
int root=infind(pre[prel],inl,inr);//找當前的根的位置
int len=root-inl;
posorder(prel+1,prel+1+len,inl,inl+len);//prel的位置是root的位置,刪去
posorder(prel+1+len,prer,inl+1+len,inr);//inl+len+1的位置是root的位置,刪去
//進行完左邊和右邊的遍歷之后,進行賦值。 左右根
pos[cnt++]=in[root];
return;
}
int main(){
int n;
while(~scanf("%d",&n)){
cnt=0;
for(int i=0;i<n;i++) cin>>in[i];
for(int i=0;i<n;i++) cin>>pre[i];
posorder(0,n,0,n);
for(int i=0;i<n;i++) cout<<pos[i]<<' ';
cout<<endl;
}
return 0;
}
//關鍵代碼:
void posorder(int prel,int prer,int inl,int inr){
if(prel==prer) return ;
int root=infind(pre[prel],inl,inr);//找當前的根的位置
int len=root-inl;
posorder(prel+1,prel+1+len,inl,inl+len);
posorder(prel+1+len,prer,inl+1+len,inr);
pos[cnt++]=in[root];//相當於輸出操作
return;
}
//得到前序遍歷的值
pos[cnt++]=in[root];//相當於輸出操作
posorder(prel+1,prel+1+len,inl,inl+len);
posorder(prel+1+len,prer,inl+1+len,inr);
//得到中序遍歷的值
posorder(prel+1,prel+1+len,inl,inl+len);
pos[cnt++]=in[root];//相當於輸出操作
posorder(prel+1+len,prer,inl+1+len,inr);
//得到后序遍歷的值
posorder(prel+1,prel+1+len,inl,inl+len);
pos[cnt++]=in[root];//相當於輸出操作
posorder(prel+1+len,prer,inl+1+len,inr);
例題:
玩轉二叉樹
https://pintia.cn/problem-sets/994805046380707840/problems/994805065406070784
題意:給你中序遍歷和前序遍歷的結果,讓你找到二叉樹的鏡像,然后按層遍歷輸出
#include <iostream>
using namespace std;
int pre[55],in[55],pos[55];
int ans[55][55];//儲存按層遍歷的結果
//第一個存的哪一層,第二個存的是具體的數,
//ans[t][0]存儲的是該層的數字個數。
int find(int t,int l,int r){
for(int i=l;i<r;i++){
if(in[i]==t){
return i;
}
}
}
void ceng(int prel,int prer,int inl,int inr,int t){
if(prel==prer) return ;
ans[t][++ans[t][0]]=pre[prel];//存入答案。
int x=find(pre[prel],inl,inr);
int len=x-inl;
ceng(prel+len+1,prer,inl+len+1,inr,t+1);//先遍歷右邊,再遍歷左邊
ceng(prel+1,prel+len+1,inl,inl+len,t+1);
return;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>in[i];
for(int i=0;i<n;i++) cin>>pre[i];
ceng(0,n,0,n,0);
int x=0;
int len=0;
while(ans[x][0]!=0){
for(int i=1;i<=ans[x][0];i++){
if(len==0){
printf("%d",ans[x][i]);
}else{
printf(" %d",ans[x][i]);
}
len++;
}
x++;
}
return 0;
}
2.已知后序、中序遍歷求前序遍歷
后序遍歷是:左右根,所以根在最后,跟前序遍歷相似,把 prel 和 prer 的值改變一下即可。
3.已知前序、后序遍歷求中序遍歷
無法求得!!!