编程之美--3.9重建二叉树
问题:
给定一棵二叉树,假定每个节点都用唯一的字符表示,具体结构如下:
struct NODE { NODE* pLeft; NODE* pRight; char chValue; };
假设已经有了前序遍历和中序遍历结果,希望通过一个算法重建这棵树。
给定函数的定义如下:
void Rebuild(char* pPreOrder, char* pInOrder, int nTreeLen, NODE** pRoot);
参数
pPreOrder:前序遍历结果的字符串数组。
pInOrder: 中序遍历结果的字符串数组。
nTreeLen: 树的长度。
pRoot: 根据前序和中序遍历结果重新构建树的根节点。
例如
前序遍历结果:a b d c e f
中序遍历结果:d b a e c f
书中使用C/C++重建二叉树,本文使用java重建二叉树,可能与书中的要求有所区别。
解:
思路:
首先取先序遍历的第一个元素p[pstart],这个元素就是整棵树的根。
然后在中序遍历序列中搜索p[pstart],位置为pos,in[pos]左侧的就是根节点左子树的所有点,数量left_num=pos-instart,in[pos]右侧的就是根节点右子树的所有点,数量right_num=inend-pos。
先序序列中p[start+1]就是根节点的左孩子,p[start+left_num+1]就是根节点的右孩子。
分别对左孩子和右孩子节点进行重建树的递归操作。
RebudeTree(lnode,pPreOrder,pstart+1,pstart+left_num,pInOrder, instart, instart+left_num-1); RebudeTree(rnode,pPreOrder,pstart+left_num+1,pend,pInOrder, instart+left_num+1, inend);
本例使用的二叉树先序遍历序列和中序遍历序列分别为
int[] pPreOrder ={24,14,13,23,45,25,38,70,50,59,95,96};
int[] pInOrder = {13,14,23,24,25,38,45,50,59,70,95,96};
二叉树的结构:
代码:
main()函数:
public static void main(String args[]){ int[] pPreOrder ={24,14,13,23,45,25,38,70,50,59,95,96}; int[] pInOrder = {13,14,23,24,25,38,45,50,59,70,95,96}; Node tree=new Node(); rebude(pPreOrder,pInOrder,11,tree); System.out.println("重建完毕"); preOrder(tree); System.out.println(); inOrder(tree); }
先序遍历和中序遍历输出结果的函数:
public static void preOrder(Node node){//先序遍历 递归 if(node!=null){ System.out.print(node.key+" "); preOrder(node.lchild); preOrder(node.rchild); } } public static void inOrder(Node node){//中序遍历 递归 if(node!=null){ inOrder(node.lchild); System.out.print(node.key+" "); inOrder(node.rchild); } }
重建二叉树函数:
//重建二叉树 public static void rebude(int[] pPreOrder, int[] pInOrder, int nTreeLen , Node reTree){ reTree.key = pPreOrder[0]; RebudeTree(reTree,pPreOrder,0,nTreeLen,pInOrder,0,nTreeLen); } //递归函数 public static void RebudeTree(Node head, int[] pPreOrder, int pstart, int pend, int[] pInOrder,int instart,int inend){ int pos = instart; //记录当前根节点在中序遍历序列中的位置 //寻找head.key(当前根节点)在中序遍历数组的位置 for( ; pos<= inend ; pos++){ if(pInOrder[pos]==pPreOrder[pstart]) break; } //确定pos之后,pos左侧的在左子树上,右侧的在右子树上 int left_num = pos-instart; //左子树节点的个数 int right_num = inend - pos; //右子树节点的个数 if(left_num<=0) head.lchild = null; if(right_num<=0) head.rchild = null; if(left_num>0){ //对左子树递归 Node lnode = new Node(); lnode.key = pPreOrder[pstart+1]; head.lchild=lnode; RebudeTree(lnode,pPreOrder,pstart+1,pstart+left_num, pInOrder, instart, instart+left_num-1); } if(right_num>0){ //对右子树递归 Node rnode = new Node(); rnode.key = pPreOrder[pstart+left_num+1]; head.rchild=rnode; RebudeTree(rnode,pPreOrder,pstart+left_num+1,pend, pInOrder, instart+left_num+1, inend); } }
结点结构:
//结点类 class Node{ Node lchild; Node rchild; int key; }
运行结果
重建完毕 先序遍历结果: 24 14 13 23 45 25 38 70 50 59 95 96 中序遍历结果: 13 14 23 24 25 38 45 50 59 70 95 96
可见,重建的二叉树遍历结果和原来的序列顺序相同

浙公网安备 33010602011771号