二叉樹的遍歷及相關操作
一、先序遍歷(根左右),中序遍歷(左根右),後序遍歷(左右根)。只是根結點的遍歷順序發生變化,但左子樹的遍歷一定在右子樹遍歷之前進行。
//先序遍歷
void preorder(node* root){
if(root==NULL)return; //遞迴邊界。
printf("%d",root->data); //訪問根結點。
preorder(root->lchild);
preorder(root->rchild);
}
二、層序遍歷(BFS)
相當於對樹從根結點開始的BFS。
void layerorder(node* root){ queue<node*>q; //此處存的是node型變數的地址 q.push(root); while(!q.empty()){ node* now=q.front(); //取對首元素 q.pop(); //出隊 printf("%d",now->data); if(now->lchild!=NULL) q.push(now->lchild); //左子樹入隊 if(now->rchild!=NULL) q.push(now->rchild); } }
若需要計算每個結點所處的層次。
struct node{ int data; int layer; //層號 node* lchild; node* rchild; } //帶層次的層序遍歷 void layerorder(node* root){ queue<node*>q; root->layer=1; q.push(root); while(!q.empty()){ node* now=q.front(); q.pop(); printf("%d",now->data); if(now->lchild!=NULL){ now->lchild->layer=now->layer+1; //子樹層號為父親結點層號+1 q.push(now->lchild); } if(now->rchild!=NULL){ now->rchild->layer=now->layer+1; q.push(now->rchild); } }
三、通過中序遍歷序列和其他三種遍歷序列之一,重建這棵二叉樹。
首先要知道三種遍歷的性質。
先序遍歷,序列中第一個數為根結點。
中序遍歷,確定根結點後,根結點左邊的序列為左子樹內容,右邊的序列為右子樹內容。
後序遍歷,序列中最後一個數為根結點。
這也論證了為什麼重建二叉樹時,一定要有中序遍歷序列,只有中序遍歷序列能區分左右子樹結點。如果知道了後序,前序和層序序列,只要不知道中序序列,就無法分辨左右子樹結點。無法唯一的重建該二叉樹。
1、通過前序和中序序列重建二叉樹。通過前序序列知道其根節點,在中序序列中找到該根節點所對應的唯一下標,由此區分左子樹區間和右子樹區間。在左子樹和右子樹中如此遞迴下去。直到先序序列長度小於等於0。例如遞迴過程中當前先序序列區間為【preL,preR】,中序序列區間為【inL,inR】。在中序序列中找到根節點下標為k。那麼左子樹結點個數 numLeft=k-inL。則先序序列中的左子樹區間為【preL+1,preL+numLeft】,右子樹區間為【preL+numLeft+1,preR】。中序序列的左子樹區間為【inL,k-1】,右子樹區間為【k+1,inR】。遞迴邊界為preL>preR。可以畫圖幫助理解。實現程式碼如下:
node* create(int preL,int preR,int inL,int inR){
if(preL>preR){
return NULL;
}
node* root=new node;
root->data=pre[preL]; // 根節點。
int k;
for(k=inL;k<inR;++k){
if(pre[preL]==in[k])break;
}
int numLeft=k-inL;
//左子樹的先序序列區間為[preL+1,preL+numLeft],左子樹的中序遍歷區間為[inL,k-1]
root->lchild=create(preL+1,preL+numLeft,inL,k-1);
//右子樹的先序序列區間為[preL+numLeft+1,preR],右子樹的中序遍歷區間為[k+1,inR]
root->rchild=create(preL+numLeft+1,preR,k+1,inR);
return root;
2、同理若通過後序序列和中序序列,重建唯一二叉樹。假設後序序列區間為【postL,postR】,中序序列區間為【inL,inR】。左子樹的結點個數為numLeft=k-inL。則後序序列中的左子樹區間為【postL,postL+numLeft-1】,右子樹區間為【postL+numLeft,postR-1】,中序序列的左子樹區間為【inL,k-1】,右子樹區間為【k+1,inR】。遞迴邊界為postL>postR。
3、通過層序遍歷序列和中序遍歷序列,重建唯一二叉樹。層序遍歷序列第一個結點就是根結點,可通過根結點和中序遍歷序列確定左右子樹結點。但在層序序列中,左右子樹結點是相互交叉在一起的。所以可以開兩個陣列分別儲存左右子樹的結點遍歷序列,相互區分。
node* create(vector<int>layer,inL,inR){
if(layer.size()==0)return NULL; //結點已經全部遍歷完成。
node* root=newNode(layer[0]); //newNode()是建立新結點函式。
int k;
for(k=inL;k<=inR;++k){
if(layer[0]==in[k])break;
}
vector<int>leftlayer; //左子樹層序遍歷序列
vector<int>rightLayer; //右子樹層序遍歷序列
for(int i=1;i<layer.size();++i){ //在整個層序遍歷序列中
bool isLeft=false;
for(int j=inL,j<k;++j){
if(layer[i]==in[j]){
isLeft=true; //找到了左子樹層序序列結點。
break;
}
}
if(isLeft)leftlayer.push_back(layer[i]);
else rightlayer.push_back(layer[i]);
}
root->lchild=create(leftlayer,inL,k-1);
root->rchild=create(rightlayer,k+1,inR);
return root;
}