部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

编程之美--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 

可见,重建的二叉树遍历结果和原来的序列顺序相同

posted @ 2015-06-29 19:28  流了个火  阅读(99)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats