一、先序遍历(根左右),中序遍历(左根右),后序遍历(左右根)。只是根结点的遍历顺序发生变化,但左子树的遍历一定在右子树遍历之前进行。
//先序遍历
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;
}