二叉树的构造

二叉树不同的遍历方式会有着不同的遍历序列,如何更具不同的遍历序列构造出二叉树呢?

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
    TreeNode():
            val(0),left(NULL),right(NULL){
    }
};

1,前序序列+,中续序列->二叉树

  • 无重复数据的二叉树的构造

    前序:1,2,3,4,5,6

    中序:2,3,1,5,4,6

    在二叉树的前序遍历中,第一个数字总是树的根节点的值,但在中序遍历中,根节点的值在序列中间,左子树的节点位于根节点的值的左边,而右子树的节点在根节点右边。

     1 void BuildTreeFromPre(TreeNode **tree,vector<int> pre,vector<int>mid){
     2     if(pre.size()==0||mid.size() == 0) return;
     3     *tree = new TreeNode(pre[0]); //构建根节点
     4     //在中序遍历找根节点
     5     int i = 0;
     6     for(i = 0;i<mid.size()&&mid[i]!=pre[0];i++);
     7     vector<int> preleft(pre.begin()+1,pre.begin()+i+1);
     8     vector<int> preright(pre.begin()+i+1,pre.end());
     9     vector<int> midleft(mid.begin(),mid.begin()+i);
    10     vector<int> midright(mid.begin()+i+1,mid.end());
    11     //构造左子树
    12     BuildTreeFromPre( &((*tree)->left),preleft,midleft);
    13     //构造右子树
    14     BuildTreeFromPre( &((*tree)->right),preright,midright);
    15 }
  • 具有重复数据的二叉树的构造

    前序:1,1,3,4,5,6

    后续:1,3,1,5,4,6

    在前序遍历中,第一个数字依然还是树的根节点,然后,在中序遍历中,可能会出现多个值与根节点相同的值,此时根据值来判断是否为根节点是行不通的。

    若在中序序列中,节点i为根节点,它将中序序列分割成左子树和右子树的中序序列。根据这些信息前序序列也可以分成左子树和右子树的前序遍历,而对于同样一棵树的前序遍历和后序遍历,元素的内容是一样的,只是顺序不同而已,也就是说他们的异或和是相等的,根据这个特点我们可以确定中序序列中的根节点。

     1 bool isRoot(vector<int> &pre,vector<int>&mid,int i){
     2     int j;
     3     int sum1 = 0,sum2=0;
     4     for(j=1;j<=i;j++){
     5         sum1 ^=pre[j];
     6     }
     7     for(j=0;j<i;j++){
     8         sum2 ^=mid[j];
     9     }
    10     return sum1==sum2;
    11 }
    12 void BuildTreeFromPre(TreeNode **tree,vector<int> pre,vector<int>mid){
    13     if(pre.size()==0||mid.size() == 0) return;
    14     *tree = new TreeNode(pre[0]); //构建根节点
    15     //在中序遍历找根节点
    16     bool findRoot=false;
    17     int i = 0;
    18     while(!findRoot){
    19         for(i = 0;i<mid.size()&&mid[i]!=pre[0];i++);
    20         if(isRoot(pre,mid,i)){
    21          findRoot = true;
    22         }
    23     }
    24     vector<int> preleft(pre.begin()+1,pre.begin()+i+1);
    25     vector<int> preright(pre.begin()+i+1,pre.end());
    26     vector<int> midleft(mid.begin(),mid.begin()+i);
    27     vector<int> midright(mid.begin()+i+1,mid.end());
    28     //构造左子树
    29     BuildTreeFromPre( &((*tree)->left),preleft,midleft);
    30     //构造右子树
    31     BuildTreeFromPre( &((*tree)->right),preright,midright);
    32     
    33 }

     需要提醒的是,具有重复数据的前序和中序遍历序列,并不能保证构成唯一的树结构,就像上面的例子,中序遍历的第一个元素和第3个元素作为根节点都是合法的。

    上面的实现的递归函数中,参数列表中都有vector向量,每次递归前都需要构造vector变量,势必会早造成额外的开销,一种改进的方式可以用向量的首尾迭代器和下标来表示有效的vector范围

2,后序序列+中序序列->二叉树

后续遍历的原理根前序遍历相同

 1 void BuildTreeFromPost(TreeNode **tree,vector<int>::iterator postBegin,vector<int>::iterator postEnd,
 2                        vector<int>::iterator midBegin,vector<int>::iterator midEnd){
 3     if(postBegin == postEnd || midBegin == midEnd) return;
 4     vector<int>::iterator p = postEnd;
 5     *tree = new TreeNode(*(p-1));
 6     for(p = midEnd; p>midBegin && *(p-1)!=*(postEnd-1);p--);
 7     BuildTreeFromPost(&(*tree)->left,postBegin,postBegin+(p-midBegin-1),midBegin,p-1);
 8     BuildTreeFromPost(&(*tree)->right,postBegin+(p-midBegin-1),postEnd-1,p,midEnd);
 9 }
10 
11 void BuildTreeFromPost(TreeNode **tree,vector<int>post,vector<int>mid){
12     BuildTreeFromPost(tree,post.begin(),post.end(),mid.begin(),mid.end());
13 }

3,层序序列

层序:1,2,4,#,3,5,6; 从每一层读取,没有元素的位置用#补上,倘若所有元素都是正整数,#可用负数代替,利用每个元素和其后代元素的位置关系构造二叉树

void BuildTree(TreeNode **tree,vector<int> vals){
  if(vals.size() == 0) return;
  TreeNode *nodes = new TreeNode[vals.size()];//创建n个节点
  for(int i=0;i<vals.size();i++){//建立这些节点的关系
      (nodes+i)->val = vals[i];
      if(2*i+1<vals.size() && vals[2*i+1]>-1){ //如果其有左孩子
           (nodes+i)->left = (nodes+2*i+1);
      }
      if(2*i+2<vals.size() && vals[2*i+2] > -1){//如果其有右孩子
           (nodes+i)->right = nodes+2*i+2;
      }
  }
  *tree = nodes;
}
Bingo,go,go,go!
原文地址:https://www.cnblogs.com/chenhaibin/p/4672091.html