zoukankan      html  css  js  c++  java
  • 07 重建二叉树

    题目描述:

    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

    测试用例:

    1)普通二叉树(完全二叉树、不完全二叉树)

    2)特殊二叉树(所有节点都没有右/左子节点的二叉树,只有一个节点的二叉树)

    3)特殊输入测试(空树:根节点指针为nullptr,输入的前序遍历序列与中序遍历序列不匹配

    解题思路:

    1)根据前序遍历序列与中序遍历序列,不断地分割成左子树与右子树,利用递归思路求解。

     

    代码:

    1)

     1 class Solution {
     2 public:
     3     TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
     4         if(pre.size()!=vin.size())
     5             return NULL;
     6         if(pre.empty())
     7             return NULL;
     8         // body
     9         TreeNode* head = new TreeNode(pre[0]);
    10         int rootNum = -1;
    11         vector<int> subPreL,subVinL,subPreR,subVinR;
    12         
    13         for(int i=0;i<vin.size();i++){
    14             if(vin[i]==pre[0]){
    15                 rootNum =i;
    16                 break;
    17             }
    18         }
    19         //left
    20         for(int i=0;i<rootNum;i++){
    21             subPreL.push_back(pre[i+1]);
    22             subVinL.push_back(vin[i]);
    23         }
    24         //right
    25         for(int i=rootNum+1;i<vin.size();i++){
    26             subPreR.push_back(pre[i]);
    27             subVinR.push_back(vin[i]);
    28         }
    29         head->left=reConstructBinaryTree(subPreL,subVinL);
    30         head->right=reConstructBinaryTree(subPreR,subVinR);
    31         return head;
    32     }
    33 };
    View Code

    注意:「1」书写要认真,确定中序遍历根结点时,由于马虎(=写成==),编译一直显示:内存超限:您的程序使用了超过限制的内存

    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
    */
    //把构建二叉树问题分解为构建左右子树问题
    //注意编写程序时,一些异常判断
    class Solution {
    public:
        TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
            //TreeNode* tree;
            if ( pre.empty()||vin.empty()|| (pre.size()!=vin.size())){
                return NULL;
            }
            return reConstructSubTree( pre, vin);
        }
        TreeNode* reConstructSubTree(vector<int> pre,vector<int> vin){
            //创建根节点
            int rootVal = pre[0];
            TreeNode* root = new TreeNode(pre[0]);
            //使用下面的方法构建root结点,会报错段错误:
            //您的程序发生段错误,可能是数组越界,堆栈溢出(比如,递归调用层数太多)等情况引起
            //TreeNode rootNode = TreeNode(rootVal);
            //TreeNode* root = &rootNode; //& 给指针赋值,取地址
    
            //终止条件,只有一个根节点,直接返回
            if ((int(pre.size())==1)&& (int(vin.size())==1)) //只有一个元素,且两个元素相等
                if (pre[0]==vin[0])  //判断是否相等,不相等则输入有误
                     return root;
                else
                    exit(1); //终止程序
            
            //还有其他结点,接着划分左右子树,再返回
            //在中序中寻找root结点位置
            vector<int> preTempL, vinTempL, preTempR, vinTempR;
            
            int rootVinIndex = -1;
            for(int i=0;i<int(vin.size());i++){ //ERROR:comparison of integers of different signs: 'int' and 'size_type'
                if(vin[i]==rootVal){
                    rootVinIndex = i;
                    break; //找到后,提前终止
                }
                //构建左子树
                preTempL.push_back(pre[i+1]);
                vinTempL.push_back(vin[i]);
            }
            if (rootVinIndex==-1)
                exit(1);  //没有找到相等的元素,说明输入有误
                //throw exception("Invalid input");
            //构建右子树
            for(int i=rootVinIndex+1;i<int(vin.size());i++){
                preTempR.push_back(pre[i]);
                vinTempR.push_back(vin[i]);
            }
            //preTempL.assign(pre.begin()+1,pre.begin()+rootVinIndex);//rootVinIndex=0时,发生段错误
            //vinTempL.assign(vin.begin(),vin.begin()+rootVinIndex-1);
            //preTempR.assign(pre.begin()+rootVinIndex+1,pre.end());
            //vinTempR.assign(vin.begin()+rootVinIndex+1,vin.end());
    
            //判断左右子树是否非空,非空--构建树
            if(!preTempL.empty())
                root->left = reConstructSubTree( preTempL, vinTempL);
            if(!preTempR.empty())
                root->right = reConstructSubTree( preTempR, vinTempR);
            
            return root;
        }

     遇到的问题:

    「1」vector assign的使用:

      preTemp.assign(first,last);  其中:preTemp时要赋值的vector变量,而指针(first,last)指向要截取的vector变量。

           -- 赋值元素包含last所指的元素,即[first,last]而不是[first,last)

           -- assign(first,last) error 不给出要赋值的变量,是错误的

           -- last指针的地址应该大于first的地址,否则会报错。即不能逆向寻址。line59-62 使用错误的原因是,当rootVinIndex=0时,addr(last)=pre.begin()<addr(first)=pre.begin()+1,报错。因此使用for循环给新分割的子树vector向量赋值。

    「2」根节点的创建 使用语句: TreeNode* root = new TreeNode(pre[0]);   new创建的变量在栈中保存,不会自动销毁,必须手动显示销毁,并不会随着局部作用域结束而结束生命。

            而语句      //TreeNode rootNode = TreeNode(rootVal);         //TreeNode* root = &rootNode; //& 给指针赋值,取地址   会报段错误  具体原因未知

    「3」line65/67判断子树是否非空:

      -- 节省不必要的操作

           -- 函数 reConstructSubTree不能处理空vector的pre与vin,在该处判断非空可以保证递归调用时,不会出现空的vector的pre与vin。

    「4」特殊输入的判断or异常处理:

           -- line16 两个vector向量不相等时,说明输入有误

           -- 保证了pre与vin输入非空,因此line23-24可以直接读取首元素并创建空节点。

           -- 当只有一个根节点时,还要判断pre与vin的这一个元素是相等的,否则输入有误。推出程序exit(1)。

           -- 在中序序列中寻找root位置时,要判断是否找到。如果没有找到,说明输入有误

           上述输入有误,针对测试实例3中输入的前序遍历序列与中序遍历序列不匹配的情况。

    基础知识:

  • 相关阅读:
    按学生成绩排序
    错误分析:floating point formats not linked
    学生成绩等级统计
    两个链表按升序合并
    js随机生成hex色值
    WEB监控系列第一篇:web监控搭建——graphite+statsd(单机搭建)
    WEB监控系列第四篇:statsd指南
    WEB监控系列第三篇:graphite指南
    安装Fedora 15后需做的25件事情
    《python tutorial》python 学习第二天
  • 原文地址:https://www.cnblogs.com/GuoXinxin/p/9973793.html
Copyright © 2011-2022 走看看