知识:在先序遍历中,第一个结点就是二叉树的根节点;而在中序遍历中,根节点必然将中序序列分割成两个子序列,前一个子序列就是根节点的左子树的中序序列,后一个是根节点的右子树的中序序列。同样,给定后序序列和中序序列,按层次序列和中序序列可以也可以唯一确定一棵二叉树。但是,如果知道二叉树的先序序列和后序序列,则无法唯一确定一棵二叉树。
例子:如给定先序序列和中序序列,建立一棵二叉树,给出重建二叉树的算法:
算法思想:使用递归思想。从先序序列中找出第一个结点,即为根节点。扫描中序序列,找到根节点的值,然后可以得到左右子树的中序序列点的集合。同时通过左右子树的大小,对先序序列进行偏移,亦可以得到左右子树的先序遍历序列。递归对左右子树进行建树。
算法步骤:
若二叉树不为空
1、传入两对指针,分别代表先序和中序序列的范围;
2、从先序列中取根节点的值;
3、创建新树的根节点,给根节点赋值,并将左右指针域初始化为NULL;
4、考虑边界条件:当序列只有一个节点的时候,如果不一样,则非法输入,否则返回新树的根指针
5、遍历中序序列,找出与先序序列中的根节点相同的节点,即根节点;
6、计算左右子树各自起始和结尾指针;
7、递归创建左右子树。
代码如下:
1 typedef struct BinTreeNode 2 { 3 int data; 4 BinTreeNode *lc; 5 BinTreeNode *rc; 6 }BinTreeNode,*BinTree; 7 8 BinTreeNode * Construct(int *preorder,int *inorder,int length) 9 { 10 if(preorder==NULL||inorder==NULL||length<=0) 11 return NULL; 12 return Constructcore(preorder,preorder+length-1,inorder,inorder+length-1); 13 } 14 15 BinTreeNode *Constructcore(int *preStart,int *preEnd,int *inStart,int *inEnd) 16 { 17 int rootVal = preStart[0];//获取根结点的值 18 BinTreeNode root = new BinTreeNode();//创建结点 19 root->data = rootVal; 20 root-lc=root->rc=NULL; 21 if(preStart == preEnd)//边界条件,只有一个结点 22 { 23 if(inStart == inEnd && *preStart == *inStart) 24 return root; 25 else 26 throw std::exception("Invalid input.");//非法输入 27 } 28 29 //在中序遍历序列中寻找根节点 30 int *inRoot = inStart; 31 while(inRoot<=inEnd && *inRoot != rootVal)//rootVal是前序遍历的根节点 32 ++inRoot;//直到找到根节点或者到中序序列结尾 33 if(inRoot == inEnd && *inRoot!=rootVal) 34 throw std::exception("Invalid input.");//当到达中序序列的结尾还没找到根节点,则说明输入的序列非法 35 int leftlen = inRoot-inStart;//指针的算术元素(减法)得到偏移量 36 int *leftPreEnd = preStart+len; 37 38 //构建子树 39 if(leftlen>0) 40 { 41 root-lc = Constructcore(preStart+1,leftPreEnd,inStart.inRoot-1); 42 } 43 if(leftlen<preEnd - preStart) 44 { 45 root-rc = Constructcore(leftPreEnd+1,preEnd,inRoot+1,inEnd); 46 } 47 48 return root; 49 }