先序+中序遍历重建二叉树

假设已知先序序列为pre1,pre2,pre3……pren,中序序列为in1,in2,in3,……,inn,如图所示,那么由先序序列的性质可知,先序序列的第一个元素pre1是当前二叉树的根节点,再由中序序列的性质可知,当前二叉树的根节点将中序序列划分为左子树和右子树。因此,要做的就是在中序序列中找到某个结点ink,使的ink==pre1,这样就在中序序列中找到了根节点。易知左子树的结点个数是numleft=k-1.于是,左子树的先序序列区间就是[2,k],左子树的中序序列区间就是[1,k-1];右子树的先序序列区间就是[2,k],右子树的中序序列区间是[k+1,n],接着只需要在左子树和右子树上进行递归重建二叉树即可。

 

事实上,如果递归过程中当前序列的区间为[prel,prer],中序序列的区间为[inl.inr],那么左子树的结点个数为numleft=k-inl.这样左子树的先序序列区间为[prel+1,prel+numleft],左子树的中序序列区间为[inl,k-1];右子树的先序序列区间为[prel+numleft+1,prer],右子树的中序序列区间为[k+1,inr];

       那么,如果一直这样递归下去,什么时候结束呢?问题的答案是显然的,因为只要先序序列的长度小于等于0时,当前二叉树就不存在了,以此作为递归的边界。

       代码如下:

//当前先序序列的区间为[prel,prer],中序序列的区间为[inl,inr]
node *create(int prel,int prer,int inl,int inr){
	if(prel>prer){
		return NULL;//先序序列长度小于等于0时,直接返回 
	}
	node *root=new node;//新建一个结点,用来存放当前二叉树的根节点 
	root->data=pre[prel];//新结点的数据域为根节点的值
	int k;
	for(k=inl,k<=inr;k++){
		if(in[k]==pre[prel])
			break;
		//在中序序列中找到in[k]==pre[l]的结点 
	} 
	int numleft=k-inl;//左子树的结点个数
	//左子树的先序区间为[prel+1,prel+numleft],中序区间为[inl,k-1]
	//返回左子树的根节点的地址,赋值给root的左指针
	root->lchild=create(prel+1,prel+numleft,inl,k-1);
	//右子树的先序序列区间为[prel+numleft+1,prer],中序区间为[k+1,inr]
	//返回右子树的根结点的地址,赋值给root的右指针
	root->rchild=create(prel+numleft+1,prer,k+1,inr); 
	return root;//返回根节点的地址 
} 

上面的代码就重建了一颗二叉树

重要结论:

中序序列可以与先序序列、后序序列和层次序列中的任意一个来重建一个唯一的二叉树,而后三者两两搭配或是三者一起都无法重建唯一的二叉树。原因是先序、后序、层次遍历均是提供根结点的,作用是相同的,都必须由中序序列来区分左子树和右子树。 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值