基于遍历序列恢复二叉树的新解法及其证明
根据二叉树的后序遍历和中序遍历还原二叉树解题方法
【题目】假设一棵二叉树的后序遍历序列为DGJHEBIFCA ,中序遍历序列为DBGEHJACIF ,则其前序遍历序列为( ) 。
A. ABCDEFGHIJB. ABDEGHJCFIC. ABDEGHJFICD. ABDEGJHCFI由题,后序遍历的最后一个值为A,说明本二叉树以节点A为根节点(当然,答案中第一个节点都是A,也证明了这一点)下面给出整个分析过程【第一步】由后序遍历的最后一个节点可知本树根节点为【A】加上中序遍历的结果,得知以【A】为根节点时,中序遍历结果被【A】分为两部分【DBGEHJ】【A】【CIF】于是作出第一幅图如下【第二步】将已经确定了的节点从后序遍历结果中分割出去即【DGJHEBIFC】---【A】此时,位于后序遍历结果中的最后一个值为【C】说明节点【C】是某棵子树的根节点又由于【第一步】中【C】处于右子树,因此得到,【C】是右子树的根节点于是回到中序遍历结果【DBGEHJ】【A】【CIF】中来,在【CIF】中,由于【C】是根节点,所以【IF】都是这棵子树的右子树,【CIF】子树没有左子树,于是得到下图【第三步】将已经确定了的节点从后序遍历中分割出去即【DGJHEBIF】---【CA】此时,位于后序遍历结果中的最后一个值为【F】说明节点【F】是某棵子树的根节点又由于【第二步】中【F】处于右子树,因此得到,【F】是该右子树的根节点于是回到中序遍历结果【DBGEHJ】【A】【C】【IF】中来,在【IF】中,由于【F】是根节点,所以【I】是【IF】这棵子树的左子树,于是得到下图【第四步】将已经确定了的节点从后序遍历中分割出去即【DGJHEB】---【IFCA】此时,位于后序遍历结果中的最后一个值为【B】说明节点【B】是某棵子树的根节点又由于【第一步】中【B】处于【A】的左子树,因此得到,【B】是该左子树的根节点于是回到中序遍历结果【DBGEHJ】【A】【C】【F】【I】中来,根据【B】为根节点,可以将中序遍历再次划分为【D】【B】【GEHJ】【A】【C】【F】【I】,于是得到下图【第五步】将已经确定了的节点从后序遍历中分割出去即【DGJHE】---【BIFCA】此时,位于后序遍历结果中的最后一个值为【E】说明节点【E】是某棵子树的根节点又由于【第四步】中【E】处于【B】的右子树,因此得到,【E】是该右子树的根节点于是回到中序遍历结果【D】【B】【GEHJ】【A】【C】【F】【I】中来,根据【B】为根节点,可以将中序遍历再次划分为【D】【B】【G】【E】【HJ】【A】【C】【F】【I】,于是得到下图【第六步】将已经确定了的节点从后序遍历中分割出去即【DGJH】---【EBIFCA】此时,位于后序遍历结果中的最后一个值为【H】说明节点【H】是某棵子树的根节点又由于【第五步】中【H】处于【E】的右子树,因此得到,【H】是该右子树的根节点于是回到中序遍历结果【D】【B】【G】【E】【HJ】【A】【C】【F】【I】中来,根据【H】为根节点,可以将中序遍历再次划分为【D】【B】【G】【E】【H】【J】【A】【C】【F】【I】,于是得到下图至此,整棵二叉树已经还原现在对该二叉树进行前序遍历便能得到我们想要的答案【B】。
基于遍历序列重构二叉结构树的分析
基于遍历序列重构二叉结构树的分析朱涛【摘要】针对如何由二叉树的遍历序列来唯一确定二叉树的问题,提出了用两种遍历序列唯一确定一棵二叉树的方法。
理论分析证明,已知先序遍历和中序遍历或者已知后序遍历和中序遍历可以唯一确定一棵二叉树,但已知后序遍历和先序遍历就不能唯一确定了。
文中还对用两种遍历序列唯一重构一棵二叉树算法进行了描述。
%An approach to confirm a unique binary tree by traversal sequence is discussed. The approach is based on confirming a unique binary tree by two kinds of traversal sequence. Theoretical analysis proved that the preorder traversed sequence and the in order traversal sequence or the post order traversal sequence and the in order traversal sequence can be used to confirm the only one binary tree. However, the post order traversal sequence and the preorder traversal sequence cannot confirm the only one binary tree. The problem has been explained in this paper.【期刊名称】《红河学院学报》【年(卷),期】2013(000)002【总页数】4页(P27-30)【关键词】遍历;遍历序列;二叉树;重构【作者】朱涛【作者单位】陕西理工学院数学与计算机科学学院,陕西汉中723000【正文语种】中文【中图分类】O18引言二叉树在计算机科学中有着重要的应用,有好多问题都是借助二叉树这种结构来描述.给定了二叉树,依据相应的遍历算法,能够方便的遍历它的所有结点,并得到相应的遍历序列.但在有些应用中,需要由二叉树的遍历序列反过来刻画它们所表示的二叉树,对于这样的问题,找出遍历序列间的关系及相应的重构方法对研究相关的问题是十分必要的.由于二叉树的基本结构是由根结点、左子树和右子树三部分构成,因此对二叉树的遍历实际上是对这三部分的遍历.对二叉树遍历以后,会得到一个线性的遍历序列,在这个线性遍历序列中,每个结点(除第一个和最后一个)有且仅有一个直接前驱和直接后继,而某一结点的直接前驱和直接后继又未必是该结点的左子树或者右子树,因此当以该序列来重新构造二叉结构树时,就难以实现.徐志烽[1]给出了一种通过先序序列和中序序列构建二叉树的算法,但文献[1]中没有给出严密的理论证明,左正康等[2]给出了后序遍历二叉树非递归算法的推导及形式化证明.但是以上研究都很少从遍历序列重构二叉树的角度给出严格的理论分析和证明.本文将对由遍历序列重新构造二叉结构树进行严格的理论分析及证明,并给出通过两种遍历序列如何唯一确定二叉结构树的实现算法.1 二叉树的遍历对二叉树的遍历运算是将二叉树中结点按一定规律线性化的过程,从这个意义上说,遍历二叉树就是将非线性化的结构变成线性化的访问序列.由二叉树的递归定义[3],二叉树的基本结构是由根结点、左子树、右子树三个基本单元组成,因此只要依次遍历了这三部分,就遍历了整个二叉树.在文献[3]中,限制结点的先左后右原则后,得到了三种二叉树遍历算法,分别称之为先(根)序遍历,记为DLR(D表示二叉树的根节点,L表示二叉树的左孩子,R表示二叉树的右孩子,文后各符号含义相同),中(根)序遍历,记为LDR,后根序遍历,记为LRD.文献[3]中还给出了下述三种不同二叉树遍历的递归算法.先序遍历算法描述为:若二叉树为空,则空操作;否则(1)访问根结点;(2)先序遍历左子树;(3)先序遍历右子树.中序遍历算法描述为:若二叉树为空,则空操作;否则(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树.图1 二叉树后序遍历算法描述为:若二叉树为空,则空操作;否则(1)后续遍历左子树;(2)后续遍历右子树;(3)访问根节点.这三种遍历算法的不同之处仅在于其对于访问根结点、左子树和右子树的先后关系不同,依据这三种算法,可分别获得不同的遍历序列,如先序遍历序列、中序遍历序列和后序遍历序列.对于图1所示的二叉树,可分别得到不同的遍历序列.先根序遍历图1所示二叉树后的先序序列为:ABCDEFGH;中根序遍历图1所示二叉树后的中序序列为:CBEDAGHF;后根序遍历图1所示二叉树后的后序序列为:CEDBHGFA.2 遍历序列重构二叉树的条件分析对于一棵非空二叉树,它的先序遍历序列、中序遍历序列或后序遍历序列有可能相同,但三种遍历序列不可能都相同.另外,每棵二叉树的先序遍历序列、中序遍历序列和后序遍历序列都是唯一的.那么对于一个给定的二叉树,要得到它的遍历序列很容易得到,反过来,由遍历序列能否确定一棵二叉树吗?是否唯一?显然,由一种遍历序列不能唯一确定一棵二叉树.本文将对三种遍历序列的组合唯一确定二叉树进行讨论.定理1:给定一棵二叉树的先序序列和中序序列,可唯一确定一棵二叉树.证明设二叉树结点的个数为n(n≥0).当n=0时,一棵空二叉树的中序序列和先序序列都为空,可以唯一确定该二叉树,命题成立.设当时命题都成立,下面证明当n=k+1时命题也成立.设一棵二叉树的中序序列和先序序列分别为a1,a2,...,ak+1和b1,b2,...,bk+1.根据二叉树的先序序列定义,b1为根,b1在a1,a2,...,ak+1中出现一次,设ai=b1( k+1).根据二叉树中序序列定义,若i=1,则左子树的中序序列为空,且左子树的先序序列也为空,若2ik+1,则a1,a2,...,ai-1为左子树的中序序列,将a1,a2,...,ai-1中的所有结点按其在b1,b2,...,bk+1中的相对次序排列成bp1,bp2,...,bpi-1( ),易知,bp1,bp2,...,bpi-1唯一,为左子树的先序序列,根据上面归纳法的假设,由于左子树的结点的个数在0到k之间,则由左子树的中序序列和先序序列可以唯一确定该左子树,同理,由右子树的中序序列和先序序列也可以唯一确定该右子树.因此,由一棵二叉树的中序序列a1,a2,...,ak+1和先序序列b1,b2,...,bk+1可以唯一确定该二叉树,即当时命题成立.定理2:给定一棵二叉树的中序序列和后序序列,可唯一确定一棵二叉树.证明:设二叉树结点的个数为n(n≥0).当n=0时,一棵空二叉树的中序序列和后序序列都为空,可以唯一确定该二叉树,命题成立.设当时命题都成立,下面证明当n=k+1时命题也成立.设一棵二叉树的中序序列和后序序列分别为a1,a2,...,ak+1和b1,b2,...,bk+1.根据二叉树的后序序列定义,bk+1为根,bk+1在a1,a2,...,ak+1中出现一次,设ai= bk+1 ( k+1).根据二叉树中序序列定义,若i=1,则左子树的中序序列为空,且左子树的后序序列也为空,若2ik+1,则a1,a2,...,ai-1为左子树的中序序列,将a1,a2,...,ai-1中的所有结点按其在b1,b2,...,bk+1中的相对次序排列成bp1,bp2,...,bpi-1(2p1p2...pi-1k+1),易知,bp1,bp2,...,bpi-1唯一,为左子树的后序序列,根据上面归纳法的假设,由于左子树的结点的个数在0到k之间,则由左子树的中序序列和后序序列可以唯一确定该左子树,同理,由右子树中序序列和后序序列也可以唯一确定该右子树.因此,由一棵二叉树的中序序列a1,a2,...,ak+1和后序序列b1,b2,...,bk+1可以唯一确定该二叉树,即当n=k+1时命题成立.定理3:给定一棵二叉树的先序序列和后序序列,可确定一棵二叉树,但不唯一.证明:由于先序序列中第一个结点是根结点,后续序列中最后面一个结点是根结点,这样,在先序序列中除第一个节点外以及在后续序列中除最后一个结点外,剩余的序列无法区分左子树和右子树,所以依据剩余的序列来构造二叉树,就会得到不同的二叉树,所以确定的二叉树不唯一.3 遍历序列重构二叉树的算法及实现根据上文分析,有两种序列组合可以唯一确定一棵二叉树,这两种序列组合分别为先序序列和中序序列以及中序序列和后序序列.张国[4]分析了递归算法和非递归算法差别,朱振元等[5]给出了一种递归算法转化为非递归算法的可能.下边对这两种组合序列重构二叉树描述了算法步骤,并对其递归实现算法进行了叙述.3.1 先序序列和中序序列重构二叉树的递归算法及实现由先序序列和中序序列重构二叉树的算法描述为:(1)若二叉树为空,返回空;(2)若不空,由先序序列得到二叉树的根结点;(3)由上述(2)的根结点把中序序列分为左子树的中序序列和右子树的中序序列两个部分;(4)根据上述左子树的中序序列个数找到对应的左子树先序序列和右子树的先序序列;(5)按上述(2)、(3)、(4)同样的方法依次类推,直到所得左、右子树只含一个结点为止.该算法的递归实现描述如下:输入参数是二叉树的先序序列preorder和中序序列inorder,长度n,返回二叉树根结点指针,bitree是结点类型名.3.2 中序序列和后序序列重构二叉树的递归算法及实现由先序序列和中序序列重构二叉树的算法描述为:(1)若二叉树为空,返回空;(2)若不空,由后序序列得到二叉树的根结点;(3)由上述(2)的根结点把中序序列分为左子树的中序序列和右子树的中序序列两个部分;(4)根据上述左子树的中序序列个数找到对应的左子树后序序列和右子树的后序序列;(5)按上述(2)、(3)、(4)同样的方法依次类推,直到所得左、右子树只含一个结点为止.该算法的递归实现描述如下:4 结束语二叉树是一种树型结构,属于典型的非线性结构,也是一种简单有效地组织数据的方式.对二叉树的遍历是对二叉树各种操作的基础,也是对二叉树进行的一种常规运算.文中主要分析了基于遍历序列重构二叉树条件,提出了两种遍历序列相结合重构二叉树的递归算法,并给出了相应算法的实现。
由遍历序列恢复二叉树
#include<stdio.h>#include<stdlib.h>#define null 0#define max 20int counter=0;typedef struct btreenode{int data;struct btreenode *lchild;struct btreenode *rchild;}bnode;int idex(char arg[],char s,int n);char pred[2*max],inod[2*max];int n=0,k0=0;bnode *restore(int l,int r,int k,char pred[],char inod[]) {int i1,i0,k1;bnode *p;p=(bnode*)malloc(sizeof(bnode));p->data=pred[k0];p->lchild=p->rchild=null;if(k0+1>r-1)return(p);i0=idex(inod,pred[k0],r+1);i1=idex(inod,pred[k0+1],r+1);k1=idex(pred,inod[i0+1],r+1);k0++;if(l<i0&&i0<=r){p->lchild=restore(k0,i0,k0,pred,inod);if(i0+1>=r&&k<i1)return(p);elseif(k>1&&i0>k1)return(p);k0++;p->rchild=restore(i0+1,r,k0,pred,inod);}else{if(i0<=1&&i0>i1)p->lchild=restore(k0,i0,k0,pred,inod);if(k1>=k0){k0++;p->rchild=restore(k0,r,k0,pred,inod);}}return(p);}int idex(char arg[],char s,int n){int i;for(i=0;i<n;i++){if(arg[i]==s)return(i);}}void print(char s[],int n){int i;for(i=0;i<n;i++)printf("%c",s[i]);printf("\n");}void prtree(bnode *p){if(p==null)return;printf("%d\t%u\t%u\t%u\t%u\n",++counter,p,p->data,p->lchild,p->rchild);if(p->lchild!=null)prtree(p->lchild);if(p->rchild!=null)prtree(p->rchild);}main(){bnode *root;char pred[max],ch;int n=0;printf("pred:");while((ch=getchar())!='\n')pred[n++]=ch;n=0;printf("inod:");while((ch=getchar())!='\n')inod[n++]=ch;root=restore(0,n-1,0,pred,inod);printf("structure of the binary tree\n");printf("counter\taddress\tdata\tlchild\trchild\n");prtree(root);printf("\n");system("pause");}。
1028.从先序遍历还原二叉树
1028.从先序遍历还原⼆叉树题⽬分析这个题其实跟我们之前序列化⼆叉树的题有点类似,这个题的难点在于怎么把对应的层次节点的⽗节点找出来,说实话想的有点久。
因为树的问题⼀般都是递归解决,所以我这次也是⽤了递归的⽅法。
具体来说就是字符串的第⼀次出现的数字必定为当前树的根节点,因为他是前序遍历。
我们可以依赖⼀个标记来记录当前所要找的层次。
因为这个是⼀棵⼆叉树,所以每次只需要分成左⼦树和右⼦树即可。
另外题⽬说了优先构建左⼦树,所以我们在实现的时候也要注意这个点。
代码实现/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/class Solution {/*** 说实话代码写的挺烂的,不过AC了* @param S* @return*/public TreeNode recoverFromPreorder(String S) {//处理空字符串if(S.length() == 0){return null;}return helper(S,1);}public TreeNode helper(String str, int level){//如果字符串为空,说明这边已经不存在节点了,直接返回空if(str.length() == 0){return null;}int j = 0;int num = 0;//处理根节点,因为根据题⽬的描述,我们的值可能不⽌⼀位,所以要逐个计算第⼀个数的数值while(j < str.length() && str.charAt(j) != '-'){num = num * 10 + Integer.parseInt(String.valueOf(str.charAt(j)));j++;}//创建根节点TreeNode root = new TreeNode(num);//这个是关键,我们定义⼀个指针,它的值为第⼀个数字结束的下标加当前的层数+1//例如 1-2-5 我们第⼀个数字结束的下标是0当前层数为1,所以我们开始遍历的下标应该为0+1+1。
根据两种遍历序列重建二叉树的算法
根据两种遍历序列重建二叉树的算法根据中序遍历和后序遍历重建二叉树:给定一棵二叉树的中序遍历序列和后序遍历序列,重建这棵二叉树。
中序遍历序列的顺序为左子树,根节点,右子树;后序遍历序列的顺序为左子树,右子树,根节点。
首先,我们可以根据后序遍历序列的最后一个元素,也就是根节点,将中序遍历序列分成左右两部分,左半部分为根节点的左子树,右半部分为根节点的右子树。
然后,我们继续按照上述方法递归处理左子树和右子树,直到子树为空或只有一个节点为止,即可得到重建的二叉树。
代码实现如下:```class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode: if not inorder or not postorder:return Noneroot = TreeNode(postorder[-1])index = inorder.index(root.val)root.left = self.buildTree(inorder[:index], postorder[:index])root.right = self.buildTree(inorder[index+1:], postorder[index:len(postorder)-1])return root```根据前序遍历和中序遍历重建二叉树:给定一棵二叉树的前序遍历序列和中序遍历序列,重建这棵二叉树。
前序遍历序列的顺序为根节点,左子树,右子树;中序遍历序列的顺序为左子树,根节点,右子树。
我们可以根据前序遍历序列的第一个元素,也就是根节点,将中序遍历序列分成左右两部分,左半部分为根节点的左子树,右半部分为根节点的右子树。
后序遍历二叉树非递归算法的推导及形式化证明
后序遍历二叉树非递归算法的推导及形式化证明后序遍历二叉树是指先遍历左子树,再遍历右子树,最后遍历根节点。
在非递归算法中,我们需要使用栈来模拟递归过程。
下面将对后序遍历二叉树非递归算法的推导及形式化证明进行详细介绍。
1. 算法思路后序遍历二叉树的非递归算法可以使用两个栈来实现。
首先将根节点压入第一个栈中,然后从第一个栈中弹出一个节点,将其压入第二个栈中。
接着依次将该节点的左子节点和右子节点压入第一个栈中。
重复上述过程,直到第一个栈为空。
最后依次从第二个栈中弹出节点,即可得到后序遍历的结果。
2. 算法证明为了证明该算法的正确性,我们需要证明两个结论:(1)每个节点都会被访问两次。
(2)第二个栈中的节点顺序即为后序遍历的结果。
对于第一个结论,我们可以使用归纳法进行证明。
假设当前节点为p,它的左子节点为q,右子节点为r。
当p第一次被访问时,它会被压入第二个栈中。
当p第二次被访问时,它会从第二个栈中弹出。
此时,p 的左子节点q和右子节点r已经被访问过了,因此它们不会再次被访问。
接着,我们需要证明q和r都会被访问两次。
对于q,它会在p第一次被访问时被压入第二个栈中,然后在p第二次被访问时被弹出。
此时,q的左子节点和右子节点都已经被访问过了,因此它们不会再次被访问。
因此,q会被访问两次。
对于r,它会在q第一次被访问时被压入第一个栈中,然后在q第二次被访问时被压入第二个栈中。
接着,r会在p第二次被访问时被弹出。
此时,r的左子节点和右子节点都已经被访问过了,因此它们不会再次被访问。
因此,r会被访问两次。
综上所述,每个节点都会被访问两次。
对于第二个结论,我们可以使用反证法进行证明。
假设第二个栈中的节点顺序不是后序遍历的结果。
设第二个栈中的节点顺序为p1,p2,...,pn。
由于后序遍历的顺序是左子树->右子树->根节点,因此对于任意的i<j,如果pi是pj的祖先节点,则pi必然在pj之前被访问。
因此,如果第二个栈中的节点顺序不是后序遍历的结果,那么必然存在两个节点pi和pj,满足pi是pj的祖先节点,但是pi在pj之后被访问。
后序遍历二叉树非递归算法的推导及形式化证明
后序遍历二叉树非递归算法的推导及形式化证明后序遍历二叉树非递归算法是一种常见的二叉树遍历方法,可以在不使用递归的情况下遍历整棵树。
本文将对后序遍历二叉树非递归算法进行推导及形式化证明。
首先,我们需要了解后序遍历的定义。
后序遍历是先遍历左子树,再遍历右子树,最后遍历根节点的一种遍历方式。
接下来,我们将推导后序遍历二叉树非递归算法。
我们可以借助栈来进行遍历,具体步骤如下:1. 定义一个栈和一个指针,指针指向根节点,栈用于存储节点。
2. 将指针指向的节点入栈,并将指针指向其左子树。
3. 循环执行以下操作:(直到栈为空)- 取出栈顶节点,判断其是否存在右子树或者是否已经被访问过。
- 如果不存在右子树或者已经被访问过,则将该节点的值输出,并弹出栈顶节点。
- 如果存在右子树且未被访问过,则将该节点的右子树入栈,并将指针指向该节点的右子树。
4. 遍历完成。
上述算法可以保证后序遍历的正确性。
接下来,我们将进行形式化证明。
首先,考虑节点在遍历时可能的情况:1. 左子树未遍历,右子树未遍历。
2. 左子树已遍历,右子树未遍历。
3. 左子树未遍历,右子树已遍历。
4. 左子树已遍历,右子树已遍历。
对于情况1,我们可以将该节点入栈,并将指针指向其左子树,进行左子树遍历。
对于情况2,我们可以将该节点入栈,并将指针指向其右子树,进行右子树遍历。
对于情况3,我们可以将该节点的值输出,并弹出栈顶节点。
对于情况4,我们可以将该节点的值输出,并弹出栈顶节点。
因此,我们可以看出,该算法对于不同情况都可以正确地进行后序遍历。
综上所述,我们成功地推导出了后序遍历二叉树非递归算法,并进行了形式化证明。
该算法简单易懂,实用性强,是二叉树遍历的重要方法之一。
通过先序遍历和中序遍历后的序列还原二叉树(实现方法)
通过先序遍历和中序遍历后的序列还原⼆叉树(实现⽅法)当我们有⼀个先序遍历序列:1,3,7,9,5,11中序遍历序列:9,7,3,1,5,11我们可以很轻松的⽤笔写出对应的⼆叉树。
但是⽤代码⼜该如何实现?下⾯我们来简单谈谈基本思想。
⾸先,先序遍历的顺序是根据根-左孩⼦-右孩⼦的顺序遍历的,那么我们可以率先确认的是先序遍历序列的第⼀个数就是根节点,然后中序遍历是根据左孩⼦-根-右孩⼦的顺序遍历的。
我们通过先序遍历确认了根节点,那么我们只需要在中序遍历中找到根节点的位置,然后就可以很好地区分出,那些属于左⼦树的节点,那些是属于右⼦树的节点了。
如下图:我们确定数字1为根节点,然后根据中序遍历的遍历顺序确定,中序遍历序列中数字1的左边全部为左⼦树节点,右边全部为右⼦树。
通过左⼦树节点的个数,得出先序遍历序列中从根节点往后的连续3个数是属于左⼦树的,剩下的为右⼦树。
这样再在左右⼦树的序列中重复以上步骤,最终找到没有⼦节点为⽌。
实现代码如下:package com.tree.traverse;import java.util.ArrayList;import java.util.List;/*** @author Caijh** 2017年6⽉2⽇下午7:21:10*/public class BuildTreePreOrderInOrder {/*** 1* / \* 3 5* / \* 7 11* /* 9*/public static int treeNode = 0;//记录先序遍历节点的个数private List<Node> nodeList = new ArrayList<>();//层次遍历节点的队列public static void main(String[] args) {BuildTreePreOrderInOrder build = new BuildTreePreOrderInOrder();int[] preOrder = { 1, 3, 7, 9, 5, 11};int[] inOrder = { 9, 7, 3, 1, 5, 11};treeNode = preOrder.length;//初始化⼆叉树的节点数Node root = build.buildTreePreOrderInOrder(preOrder, 0, preOrder.length - 1, inOrder, 0, preOrder.length - 1);System.out.print("先序遍历:");build.preOrder(root);System.out.print("\n中序遍历:");build.inOrder(root);System.out.print("\n原⼆叉树:\n");build.prototypeTree(root);}/*** 分治法* 通过先序遍历结果和中序遍历结果还原⼆叉树* @param preOrder 先序遍历结果序列* @param preOrderBegin 先序遍历起始位置下标* @param preOrderEnd 先序遍历末尾位置下标* @param inOrder 中序遍历结果序列* @param inOrderBegin 中序遍历起始位置下标* @param inOrderEnd 中序遍历末尾位置下标* @return*/public Node buildTreePreOrderInOrder(int[] preOrder, int preOrderBegin, int preOrderEnd, int[] inOrder, int inOrderBegin, int inOrderEnd) {if (preOrderBegin > preOrderEnd || inOrderBegin > inOrderEnd) {return null;}int rootData = preOrder[preOrderBegin];//先序遍历的第⼀个字符为当前序列根节点Node head = new Node(rootData);int divider = findIndexInArray(inOrder, rootData, inOrderBegin, inOrderEnd);//找打中序遍历结果集中根节点的位置int offSet = divider - inOrderBegin - 1;//计算左⼦树共有⼏个节点,节点数减⼀,为数组偏移量Node left = buildTreePreOrderInOrder(preOrder, preOrderBegin + 1, preOrderBegin + 1 + offSet, inOrder, inOrderBegin,inOrderBegin + offSet); Node right = buildTreePreOrderInOrder(preOrder, preOrderBegin + offSet + 2, preOrderEnd, inOrder, divider + 1, inOrderEnd);head.left = left;head.right = right;return head;}/*** 通过先序遍历找到的rootData根节点,在中序遍历结果中区分出:中左⼦树和右⼦树* @param inOrder 中序遍历的结果数组* @param rootData 根节点位置* @param begin 中序遍历结果数组起始位置下标* @param end 中序遍历结果数组末尾位置下标* @return return中序遍历结果数组中根节点的位置*/public int findIndexInArray(int[] inOrder, int rootData, int begin, int end) {for (int i = begin; i <= end; i++) {if (inOrder[i] == rootData)return i;}return -1;}/*** ⼆叉树先序遍历结果* @param n*/public void preOrder(Node n) {if (n != null) {System.out.print(n.val + ",");preOrder(n.left);preOrder(n.right);}}/*** ⼆叉树中序遍历结果* @param n*/public void inOrder(Node n) {if (n != null) {inOrder(n.left);System.out.print(n.val + ",");inOrder(n.right);}}/*** 还原后的⼆叉树* ⼆叉数层次遍历* 基本思想:* 1.因为推导出来的⼆叉树是保存在Node类对象的⼦对象⾥⾯的,(类似于c语⾔的结构体)如果通过递归实现层次遍历的话,不容易实现* 2.这⾥采⽤List队列逐层保存Node对象节点的⽅式实现对⼆叉树的层次遍历输出* 3.如果⽗节点的位置为i,那么⼦节点的位置为,2i 和 2i+1;依据这个规律逐层遍历,通过保存的⽗节点,找到⼦节点。
根据前序遍历和中序遍历结果还原二叉树
根据前序遍历和中序遍历结果还原⼆叉树本⽂代码为java代码⼀、⼆叉树⼆叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空⼆叉树),或者由⼀个根节点和两棵互不相交的,分别称为根节点的左⼦树和右⼦树的⼆叉树组成。
--《⼤话数据结构》简单的说,⼆叉树是⼀种树,并且最多有2个⼦树。
如图1-1:代码表⽰:public class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int x) { val = x; }}⼆、⼆叉树的遍历1、前序遍历前序遍历的顺序是,根节点->左⼦树->右⼦树,遍历⼦树时也按照相同的顺序,可以⽤递归的思想理解。
遍历顺序如图2-1:代码表⽰:public static void prevPrintTreeNode(TreeNode root){if(root == null){return;}System.out.print(root.val+" ");//运⽤了递归prevPrintTreeNode(root.left);prevPrintTreeNode(root.right);}所以结果是:{1,2,3,4,5,6}。
可知前序遍历结果的第⼀个节点为根节点。
2、中序遍历中序遍历的顺序是,左⼦树->根节点->右⼦树。
遍历顺序如图2-2:代码表⽰,只有顺序的区别:public static void inPrintTreeNode(TreeNode root){if(root == null){return;}//运⽤了递归inPrintTreeNode(root.left);System.out.print(root.val+" ");inPrintTreeNode(root.right);}所以结果是:{3,2,1,5,4,6}。
由遍历序列恢复二叉树
由遍历序列恢复⼆叉树
由于三种序列中的任意⼀种系列都不能完整的画出⼆叉树,但是已知其中⼆种遍历序列便可推算出原始⼆叉树。
通过先序和中序或者中序和后序都可以还原原始⼆叉树,但是已知先序和后序是⽆法还原出原始⼆叉树的。
换种说法:只有通过先序和中序,或中序和后序才能唯⼀的确定⼀个⼆叉树。
在这⾥,先序中序和后序的规则不做解释。
⼀、已知先序和中序求后序
已知先序为:ABCDEFGH 中序为:BDCEAFHG
1.先序的第⼀位为根节点,所以A为根节点。
2.中序中根节点左边为左⼦树,右边为右⼦树,所以BDCE为左⼦序列,FHG为右⼦序列
3.先序中左⼦序列先出现的为⼦序列的根节点,所以B为左⼦序列的根节点
4.再次回到中序序列中,左⼦序列的根节点左边为其左⼦序列,右边为其右⼦序列,所以⼦序列的根节点⽆左⼦序列,右⼦序列为DCE。
5.同理,推测下⼀阶的⼦序列和根节点的右序列
由此推出后序为:DECBHGFA
⼆、已知中序和后序求先序:
已知中序为:BDGEAFHG 中后序为:DECBHGFA
1.后序的最后⼀个为根节点,所以A为根节点
2.中序中根节点左边为左⼦树,右边为右⼦树,所以BDGE为左⼦树,FGH为右⼦树
3.后序中左⼦序列的中最后出现的为左⼦序列的根节点,所以B为左⼦序列的根节点
4.再次回到中序中,左⼦序列根节点的左侧为其左⼦序列,右侧为其右⼦序列,所以B⼦序列⽆左⼦序列,右⼦序列为DEG。
5.同理,推测出B的其他⼦序列以及跟节点的整个右⼦序列。
由此推出先序为:ABCDEFGH
其实,细⼼的同学可能会发现,这两个例⼦的图怎么⼀样呢。
通过层序和中序遍历序列重建二叉树
通过层序和中序遍历序列重建⼆叉树 在学⼆叉树的重建时,在《算法笔记》上学到了如何通过先序(或后序)遍历序列和中序遍历序列重建⼆叉树,它也提出了⼀个问题:如何通过层序和中序遍历序列重建⼆叉树?我⼀开始按照先序和中序重建的思路思考,发现做不到。
我⽆法确定⼀个点后⾯的点属于它的左⼦树还是右⼦树或者兄弟节点。
于是我在⽹上查找,发现这⽅⾯的话题不多,其中还有⼀些不是⽤C++实现的。
不过幸好还是找到了。
于是在学习之后在这把它记录下来。
1 #include <cstdio>23const int INF = 0x3fffffff;4const int maxn = 10010;56struct Node7 {8int x;9 Node *left, *right;10 };1112 Node* root;13int levelorder[maxn], inorder[maxn];14int n;15bool hashtable[maxn]; //标记levelorder中某个点是否被加⼊了树中16//如果没有hashtable, 当树中存在两个值相等的点时,17 Node* init() //可能导致在层序遍历中相同值的两个点前⾯的点被遍历两次,后⾯的点18 { //没有被遍历,从⽽建树错误19 Node* node = new Node;20 node->x = 0;21 node->left = NULL;22 node->right = NULL;23return node;24 }2526 Node* buildtree(int il, int ir, int ll, int lr) //当我给你⼀个⼆叉树的中序遍历时27 { //这个中序遍历遍历⼀定有⼀个根节点28if(il == ir) //体现在层序遍历上时它⼀定先出现29 { //所以顺序遍历层序遍历,⼀定可以先发现⼆叉树的根节点30 Node* node = new Node;31 node->x = inorder[il];32 hashtable[il] = true;33return node;34 }35 Node* node = new Node;36int i, j;37for(j = ll; j <= lr; j++)38 {39bool flag = false;40for(i = il; i <= ir; i++)41 {42if(inorder[i] == levelorder[j]&&hashtable[i] == false)43 {44 flag = true;45break;46 }47 }48if(flag) break;49 }50 node->left = buildtree(il, i-1, j+1, lr);51 node->right = buildtree(i+1, ir, j+1, lr);52 node->x = inorder[i];53 hashtable[i] = true;54return node;55 }5657int main()58 {59 scanf("%d", &n);60for(int i = 0; i < n; i++) scanf("%d", &inorder[i]);61for(int i = 0; i < n; i++) scanf("%d", &levelorder[i]);62 root = buildtree(0, n-1, 0, n-1);63 printf("%d\n", root->left->right->x);64return0;65 } 这个重建的⽅法利⽤了层序遍历序列中⽗⼦节点有先后顺序的特点。
先序中序遍历__还原二叉树
先序中序遍历__还原⼆叉树4-1-⼆叉树及其遍历还原⼆叉树 (25分)给定⼀棵⼆叉树的先序遍历序列和中序遍历序列,要求计算该⼆叉树的⾼度。
输⼊格式:输⼊⾸先给出正整数N(≤50),为树中结点总数。
下⾯两⾏先后给出先序和中序遍历序列,均是长度为N的不包含重复英⽂字母(区别⼤⼩写)的字符串。
输出格式:输出为⼀个整数,即该⼆叉树的⾼度。
输⼊样例:9ABDFGHIECFDHGIBEAC输出样例:5解题思路1.树是递归定义的,⼀定要记住这句话所以⼀个树的先序遍历,他的根的左右⼉⼦也是先序遍历中序遍历同理我们拿样例来模拟然后再把左⼦树的两种序列进⾏处理稍加计算出起始位置就⾏了然后递归处理就可以,剩下的就不模拟了中序遍历同理2.先序遍历的第⼀个节点就是根节点3.找到先序的根节点之后,在中序⾥⾯找到这个值该值左边序列的就是左⼦树的先序遍历,右边的就是右⼦树的然后在先序遍历中,数相同的长度左⼦树的先序遍历,递归操作即可#include<cstdio>#include<algorithm>#include<cstdlib>using namespace std;typedef struct Node* Tree;struct Node{Tree lt,rt;char v;};int ans;char xx[55],zx[55];Tree MakeNode(){Tree T=(Tree)malloc(sizeof(struct Node));T->lt=T->rt=NULL;return T;}Tree MakeTree(int xh,int zh,int s){Tree T=MakeNode();T->v=xx[xh];if(s==1)return T;for(int i=zh;i<=zh+s-1;i++){if(xx[xh]==zx[i]){if(i>zh)T->lt=MakeTree(xh+1,zh,i-zh);if(i<zh+s-1)T->rt=MakeTree(xh+i-zh+1,i+1,s-i+zh-1);}}return T;}void bl(Tree T,int h){if(T->lt)bl(T->lt,h+1);if(T->rt)bl(T->rt,h+1);ans=ans>h?ans:h;}int main(){int n;scanf("%d",&n);scanf("%s%s",xx,zx);Tree T=MakeTree(0,0,n);bl(T,1);printf("%d",ans);}。
物理毕业论文二叉树的遍历研究及还原研究
二叉树的遍历研究及还原研究摘要:通过对同一棵二叉树三种遍历方式的分析,概括出由前序、中序或由中序、后序遍历结果快速还原二叉树的方法。
? 关键词:二叉树;二叉树的遍历;二叉排序树;还原? ?二叉树是最为常用的数据结构,它的实际应用非常广泛。
二叉树的遍历方式有三种,前序遍历、中序遍历、后序遍历。
先序遍历的顺序为:NLR,即先根结点,然后左子树、右子树;中序遍历顺序为:LNR先左子树,然后根结点、右子树;后序遍历顺序为:LRN先左子树、然后右子树、根结点。
由前序和中序遍历、由中序和后序遍历序列可以唯一确定一棵二叉树,而由前序和后序遍历序列不能唯一确定一棵二叉树。
? 二叉排序树对二叉树作了进一步的限定:根结点的权值大于(或小于)左子树中所有结点的权值;根结点的权值小于(或大于)其右子树中所有结点的权值。
? 那么如何根据三种遍历序列之间的关系及二叉排序树来快速还原一棵二叉树?下面以二叉树的前序和中序遍历序列为基础,利用二叉排序树的性质,给出快速还原二叉树的方法。
? 1由给定前序和中序序列或中序和后序序列还原二叉树的方法? 例:前序序列:ABDECFGH 中序序列:DEBACGFH (后序序列:EDBGHFCA)? (1)给中序序列中的每个结点从小到大、从左到右赋以权值,如下:? D(1)E(2)B(3)A(4)C(5)G (6)F(7)H(8)? (2)还原时读入的序列为前序序列,从左到右依次读入序列中的各个结点值和相应的权值; ?(3)由读入的序列,根据第1)步中给定的权值按照二叉排序树的构造规则构造二叉排序树。
第一个读入的结点为根结点,其他结点分别为左右子树中的结点。
设根结点为TT,权值为NN,当前读入结点为SS,权值为MM,若MM (4)将SS插入到TT的左子树或右子树的过程中,仍然遵循3)中的规则,直至左子树或右子树为空时止。
? (5)读入序列结束时,二叉树还原成功。
还原后的二叉树如下图。
? (6)对于由中序序列和后序序列还原二叉树是,读入的序列为后序序列,从右向左读入,构造规则同上。
二叉树的遍历详解及实现
⼆叉树的遍历详解及实现在之前的博⽂中我们讲解了⼆叉树的使⽤——《哈夫曼压缩》,那么,我们对于⼆叉树的操作不仅仅局限于创造,⼆叉树是⼀种储存处理⽅式,但是,我们不能仅仅是存储数据,那么,我们今天就来讲解⼀下从⼆叉树中读取数据的⽅法及操作。
⼆叉树的遍历⽅式有三种:1.先根序:根、左⼦树、右⼦树2.中根序:左⼦树、根、右孩⼦3.后根序:左⼦树、右⼦树、根现在通过⼀个例⼦来为,我让⼤家清晰了解们这三种遍历⽅法:对于这个⼆叉树来说:先根序遍历结果:A B D F G J C E H I中根序遍历结果:F D J G B A H E I C后根序遍历结果:F J G D B H I E C A现在我们来构造⼀个⼆叉树,然后对这个⼆叉树进⾏遍历操作:⾸先,我们按照我们之前博⽂中⼀直有的惯例,上⼿先编写"mec.h":#ifndef _MEC_H_#define _MEC_H_typedef unsigned char boolean;typedef boolean u8;#define TRUE 1#define FALSE 0#define NOT_FOUND -1#define SET(v, i) (v |= (1 << ((i) ^ 7)))#define CLR(v, i) (v &= ~(1 << ((i) ^ 7)))#define GET(v, i) (((v) & (1 << ((i) ^ 7))) != 0)#endif之后,我们再来构建⼆叉树“单节点”结构体:typedef struct BTREE {int data;struct BTREE *left;struct BTREE *right;}BTREE;那么,我们要构建⼆叉树,就要从键盘输⼊⼀个字符串,再读取字符串判断字符串输⼊是否合理,再根据正确的字符串构建⼆叉树。
C语言从前序遍历结果(数组)中序遍历结果(数组)还原树的算法
C语言从前序遍历结果(数组)中序遍历结果(数组)还原树的算法根据前序遍历和中序遍历结果还原二叉树,需要使用递归的方式实现。
下面是具体的算法步骤:1.定义树的结构体,包含一个值和左、右子树的指针。
```cstruct TreeNodeint val;struct TreeNode* left;struct TreeNode* right;};```2. 实现递归函数`buildTree`,该函数接受前序遍历数组`preorder`、中序遍历数组`inorder`、前序遍历的起始索引`preStart`、前序遍历的结束索引`preEnd`、中序遍历的起始索引`inStart`和中序遍历的结束索引`inEnd`作为参数,返回构建完成的二叉树的根节点。
函数主要分为两个步骤:- 第一步,找到根节点的值:根节点的值为前序遍历数组的第一个元素`preorder[preStart]`。
- 第二步,根据根节点的值切分中序遍历数组,找到根节点在中序遍历数组中的位置`rootIndex`,并计算出左子树元素的个数`leftNum`。
3.递归构建左子树和右子树:- 左子树的前序遍历数组范围为`preStart + 1`到`preStart + leftNum`,中序遍历数组范围为`inStart`到`rootIndex - 1`。
- 右子树的前序遍历数组范围为`preStart + leftNum + 1`到`preEnd`,中序遍历数组范围为`rootIndex + 1`到`inEnd`。
4.返回根节点。
下面是完整的代码实现:```cstruct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize)if (preorderSize == 0 , inorderSize == 0)return NULL;}//创建根节点struct TreeNode* root = (structTreeNode*)malloc(sizeof(struct TreeNode));root->val = preorder[0];//在中序遍历数组中找到根节点的位置int rootIndex;for (int i = 0; i < inorderSize; i++)if (inorder[i] == root->val)rootIndex = i;break;}}//计算左子树元素的个数int leftNum = rootIndex - inStart;//递归构建左子树和右子树root->left = buildTree(preorder + 1, leftNum, inorder, rootIndex);root->right = buildTree(preorder + leftNum + 1, preorderSize - leftNum - 1, inorder + rootIndex + 1, inorderSize - rootIndex - 1);return root;```这个算法的时间复杂度为O(n^2),其中n是树的节点个数。
由遍历结果还原二叉树的递归算法
由遍历结果还原二叉树的递归算法
陈文
【期刊名称】《电脑知识与技术》
【年(卷),期】2009(005)018
【摘要】二又树的遍历操作和其它操作的算法实现,都必须先创建二叉树.分析常规创建二叉树方法的特点和不足,给出利用中序遍历和后序遍历结果还原二叉树的算法,利用这一方法,给出由前序遍历和后序遍历还原二叉树的算法,最后,提供利用次层遍历和中序遍历还原二叉树的算法.
【总页数】3页(P4759-4761)
【作者】陈文
【作者单位】福州职业技术学院,计算机系,福建,福州,350108
【正文语种】中文
【中图分类】TP311
【相关文献】
1.二叉树的先序遍历和中序遍历的非递归算法 [J], 黄霞
2.二叉树后序遍历非递归算法的改进研究 [J], 章晓勤
3.一种新的二叉树后序遍历的非递归算法 [J], 张建波
4.二叉树中序遍历在汉诺塔递归算法教学中的应用 [J], 杨建华
5.中序遍历二叉树的非递归算法研究 [J], 吴昊
因版权原因,仅展示原文概要,查看原文内容请购买。
前序遍历中序遍历复原方法
前序遍历中序遍历复原方法树是一种非线性的数据结构,它的一个重要性质就是可以通过不同的遍历顺序来表达树的结构。
在二叉树中,常用的三种遍历方式有前序遍历、中序遍历和后序遍历。
这三种遍历方式可以帮助我们了解树的结构,从而实现一些操作,比如复原树的结构。
在本文中,我们将讨论如何通过前序遍历和中序遍历的结果来复原一棵树的结构。
前序遍历、中序遍历和后序遍历是树的三种深度优先遍历方式。
它们的定义如下:-前序遍历:先访问根节点,再依次遍历左子树和右子树。
-中序遍历:先遍历左子树,再访问根节点,最后遍历右子树。
-后序遍历:先遍历左子树,再遍历右子树,最后访问根节点。
在这三种遍历方式中,前序遍历和中序遍历是最常用的。
在实际应用中,有时我们只能得到树的前序遍历和中序遍历结果,但想要还原树的结构。
那么,该如何通过前序遍历和中序遍历的结果来复原一棵树的结构呢?为了解决这个问题,我们首先需要知道前序遍历和中序遍历的性质。
在前序遍历中,第一个元素一定是根节点,在中序遍历中,根节点左边的元素都位于左子树中,根节点右边的元素都位于右子树中。
利用这些性质,我们可以进行如下步骤来复原树的结构:1.根据前序遍历的结果确定根节点。
2.在中序遍历的结果中找到根节点的位置,划分出左子树和右子树。
3.递归处理左子树和右子树,直到无法再继续递归。
下面,我们以一个具体的例子来说明如何通过前序遍历和中序遍历的结果来复原一棵树的结构。
假设我们有以下一棵树的前序遍历结果为[1,2,4,5,3,6,7],中序遍历结果为[4,2,5,1,6,3,7]。
我们需要还原这棵树的结构。
首先,根据前序遍历的结果,我们可以知道根节点是1、然后,在中序遍历的结果中找到根节点1的位置,左子树为[4,2,5],右子树为[6,3,7]。
接下来,我们递归处理左子树和右子树。
对于左子树,前序遍历结果为[2,4,5],中序遍历结果为[4,2,5]。
根据前序遍历的结果,我们可以知道左子树的根节点是2、在中序遍历的结果中找到根节点2的位置,左子树为空,右子树为[4,5]。
二叉树还原规律
二叉树还原规律二叉树是一种常见的数据结构,它由节点和边组成,每个节点最多有两个子节点。
在二叉树中,有一种重要的操作叫做还原,即根据已知的规律或条件,将二叉树恢复到原始状态。
本文将探讨二叉树还原的规律和方法。
我们需要了解二叉树的基本概念。
二叉树由根节点、左子树和右子树组成。
根节点是二叉树的起始节点,左子树和右子树分别是根节点的左边和右边的子树。
每个节点可以有零个、一个或两个子节点。
如果一个节点没有子节点,我们称之为叶子节点;如果一个节点有两个子节点,我们称之为内部节点。
另外,每个节点都有一个值,用来存储数据。
在还原二叉树的过程中,我们需要根据已知的规律或条件来确定二叉树的结构。
常见的还原规律包括前序遍历、中序遍历和后序遍历。
前序遍历是指从根节点开始,先遍历根节点,然后遍历左子树,最后遍历右子树。
在前序遍历中,根节点的值总是在其左右子节点之前被访问到。
如果我们知道一个二叉树的前序遍历结果,就可以根据这个结果还原出原始的二叉树。
中序遍历是指从根节点开始,先遍历左子树,然后遍历根节点,最后遍历右子树。
在中序遍历中,根节点的值总是在其左右子节点之间被访问到。
如果我们知道一个二叉树的中序遍历结果,就可以根据这个结果还原出原始的二叉树。
后序遍历是指从根节点开始,先遍历左子树,然后遍历右子树,最后遍历根节点。
在后序遍历中,根节点的值总是在其左右子节点之后被访问到。
如果我们知道一个二叉树的后序遍历结果,就可以根据这个结果还原出原始的二叉树。
除了以上三种遍历方式,还有一种特殊的遍历方式叫做层序遍历。
层序遍历是从上到下、从左到右依次访问每个节点。
如果我们知道一个二叉树的层序遍历结果,就可以根据这个结果还原出原始的二叉树。
在还原二叉树的过程中,我们可以使用递归或迭代的方式来实现。
递归是一种自身调用的方法,可以简化问题的解决过程。
在还原二叉树时,递归可以根据已知的规律或条件,不断地将问题分解成更小的子问题,直到达到最小的情况,然后再逐步合并子问题的解答,最终得到原始二叉树。
前序遍历 中序遍历 复原方法
前序遍历中序遍历复原方法以前序遍历、中序遍历复原二叉树的方法在计算机科学中,二叉树是一种常见的数据结构,它由节点组成,每个节点最多有两个子节点。
二叉树的遍历是指按照特定的顺序访问二叉树的所有节点。
常见的遍历方式有前序遍历、中序遍历和后序遍历。
前序遍历是指首先访问根节点,然后递归地访问左子树,最后递归地访问右子树。
中序遍历是指首先递归地访问左子树,然后访问根节点,最后递归地访问右子树。
而后序遍历是指首先递归地访问左子树,然后递归地访问右子树,最后访问根节点。
在某些情况下,我们可能只知道二叉树的前序遍历和中序遍历的结果,希望能够复原出原始的二叉树。
这种情况下,我们可以利用前序遍历和中序遍历的特性来进行复原。
我们需要了解前序遍历和中序遍历的特点。
在前序遍历中,第一个访问的节点是根节点,而在中序遍历中,根节点位于左子树和右子树的中间位置。
基于这一特点,我们可以通过前序遍历的第一个节点确定根节点,并在中序遍历中找到根节点的位置。
接下来,我们可以利用中序遍历的特点划分出左子树和右子树。
根据根节点在中序遍历中的位置,我们可以确定左子树和右子树的节点个数。
然后,我们可以利用前序遍历和中序遍历的切片操作,分别得到左子树和右子树的前序遍历和中序遍历结果。
通过递归地重复上述步骤,我们可以不断复原出左子树和右子树,最终得到完整的二叉树。
下面,我将通过一个具体的例子来演示前序遍历和中序遍历复原二叉树的方法。
假设我们有以下前序遍历和中序遍历结果:前序遍历:[1, 2, 4, 5, 3, 6, 7]中序遍历:[4, 2, 5, 1, 6, 3, 7]根据前序遍历的第一个节点1,我们确定根节点为1。
然后,在中序遍历中找到根节点1的位置,可以得知左子树的中序遍历为[4, 2, 5],右子树的中序遍历为[6, 3, 7]。
接下来,我们可以利用左子树和右子树的中序遍历结果来得到左子树和右子树的前序遍历结果。
左子树的前序遍历为[2, 4, 5],右子树的前序遍历为[6, 3, 7]。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
于遍历序列恢复二叉树 的各种 可能 , 用数学归纳法 证明其可行性 , 并在文献 [ 8 ] 给 出了基 于前序 和后
序序 列恢 复无 1度 结 点二 叉 树 的 实现 算 法 . 但 上述
据问题求解时结点使用的不 同情形 , 将结点分作不 同状态 . 这些 状态 的变迁 , 是 问题 求解 从初 始情形 向
Vo l _ 3 7 No . 3
Ma v 2 01 3
文章编 号 : 1 0 0 0 - 5 8 6 2 ( 2 0 1 3 ) 0 3 4 3 2 6 8 - 0 5
基 于 遍 历 序 列 恢 复 二 叉 树 的新 解 法 及 其 证 明
化 志章
( 江 西 师 范大 学 计 算 机 信 息 工 程 学 院 , 江西 南昌 3 3 0 0 2 2 )
了函数式 风格 的前序 +中序恢 复树 算 法. 开 发 过程 中需 要 引 入 大 量 的专 业 数 学 知 识 , 属 于 数 学 家 的
开 发.
基 于状态 变迁 的思想 构造 了二叉树 后序遍 历非 递 归算 法 _ l , 并 通 过 参 数 变 换 获 得 二 叉 树 前 序 遍
第3 7卷 第 3期 2 0 1 3年 5月
江西师 范大 学学报 (自然科 学 版 ) J o u na r l o f J i a n g x i N o r m a l U n i v e r s i t y ( N a t u r a l S c i e n c e )
着 不 同的含义 , 必 须要 明确 区分 . 基 于 上 述考 虑 , 根 均 为0 ( ) ; E . M a k i n e n L 6 提出的新算法侧重于减少恢
复过程 中比较次数 ; 唐 自立 较 为 系统 地 分 析 了基
最终情 形变 迁 的基 本操 作. 进一 步拓 展 , 以结点状 态 及影 响结点 状态 变迁 的所有相 关数 据为基 础构造 程
研究提出的算法均 由分析获得 , 并未对算法本身的
收 稿 日期 : 2 0 1 3 - 0 1 — 1 2
基金项 目: 江西省教育厅科技课题 ( G J J 0 9 1 4 2 ) 资助项 目.
系统性 地研 究 了现有 的恢 复二 叉 树 算法 , 发 现 有 些 算法存 在错 误 , 并 进行 了修正 . 遗憾 的是他 同样 未对 所提 算法正 确性 进行 证 明. 有 别 于传 统 的命 令 式 算 法形 式 ; S . C . Mu等 使 用 B i r d — Me e  ̄ e n s 演 算 给 出
摘要: 提出了一种基于前序和中序遍历序列恢复二叉树的解法 , 算法以数学公式形式呈现, 反映了建树
过程 中相关数据变化的一般规 律 , 具备数学上的引用透明性 , 由此能机械获得非递归程序 和循 环不变式 ,
并进行 了正确性证明. 通过简单变换 , 获得 了后序 +中序 、 前序 + 后 序恢复 二叉 树 的可信 算法. 实验效果 表 明了该解法 的有效性.
A. A n d e r s s o n等 _ 5 对 G e n — H u e y C h e n的 时 间优 先 算
1 基于状态变迁思想的可信算法构造
基于非线性结构的数据应用有较多隐含信息需
要考 虑 , 如二叉 树 结 点 t 包 含 数 据 域 和 左 右孩 子 等 信 息. 在设 计非 递归 的基 于遍 历恢 复二叉 树算 法时 , t 的数 据 域 已知 、 左 孩 子 已知 或 右 孩 子 已知等 代 表
作者简介 : 化志章( 1 9 7 2 . ) , 男, 安徽萧县人 , 副教授 , 硕士 , 主要从事算法形式推导和软件验证等方 面的研究
第3 期
化志章 : 基于遍历序列恢复二叉树 的新解法及其证明
关键词 : 状态变迁; 二叉树遍历; 恢复二叉树 ; 循环不变式
中图分 类号 : r r P 3 1 1 . 1
文献标 志码 : A
正确性 进行 证 明 , 结 果 难 以令 人 信 服. N. A r o r a等
0 引言
二叉 树是 一种 简 单 的非 线 性结 构 , 在编 译 器 构 造、 数据 挖掘 、 人工 智 能 等领 域 有 着广 泛 应 用 . 二 叉 树 相关算 法 的形式 化 开 发及 证 明 , 对 基 于非 线 性 结 构 的可 信算法 构造 有 着 重要 的借 鉴 意义 . 遍 历 是 二 叉 树最 基本操 作 , 而基 于遍 历 序列 恢 复 二 叉树 常 被 视 为遍 历 的逆 过程 , 并有 着 与遍历操 作类 似 的特性 . 构造递 归算 法很 容易 , 构造非 递归 算法则 较 困难. D . E . K n u t h … 将基 于遍历 恢 复二 叉树 视 为有 趣
变换 的 学 者 则 将 其 作 为 经 典 的程 序 问 题 进 行 处 理 J , 产生 较多非 递归 算 法. H . A. B u r g d o r f等 给
出了时间为 0 ( n ) 的非递归算 法, G e n — H u e y C h e n
等 从 时 间优 先 和 空 间 优 先 角 度 给 出 2个 恢 复 二 叉 树 的算 法 , 其 中时间优先 算法 需要借 助 哈希存储 , 而空 间优 先算 法需 要 0 ( N l o g N) 时间和 0( N) 空间;
历、 中序 遍历 以及 K叉 树 前 序遍 历 和后 序遍 历 的 非 递 归算 法 , 算 法 以数 学公 式方式 呈现 , 比现 有算法 简 洁. 本 文将状 态变 迁思 想 应 用 于基 于 遍 历序 列 恢 复
二叉 树 , 同样 收 到了较好 效果 .
的算法问题 , 对其可行性进行了简单解释. 研究程序