二叉树的遍历及相关操作

一、先序遍历(根左右),中序遍历(左根右),后序遍历(左右根)。只是根结点的遍历顺序发生变化,但左子树的遍历一定在右子树遍历之前进行。

//先序遍历
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;
}
    

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值