前序遍历和中序遍历来重构二叉树

前序遍历序列:根左右,序列第一个数字一定是根节点值。其后分别是左子树序列和右子树序列。

中序遍历序列:左根右,根节点在中间,根节点左侧是左子树,根节点右侧是右子树。

后序遍历序列:左右根,根节点在最后。

以下两种方式其实是一种思想:先从前序遍历序列第一个位置找到根节点值,创建树节点,通过这个值再在中序遍历序列中找到根节点所在位置。然后分出根节点左右子树的前序和中序序列,进行递归创建root节点。

二叉树中所有节点都可以看成子树的根节点。

指针用法:

       struct TreeNode {
       int val;
       TreeNode *left;
       TreeNode *right;
       TreeNode(int x) : val(x), left(NULL), right(NULL) {}
       };  
        TreeNode* ConstructCore(int* startPre, int* endPre, int* startIn, int* endIn){
        //前序遍历序列的第一个数字是根节点的值
        int rootValue = startPre[0];
        //创建根节点
        TreeNode* root = new TreeNode(rootValue);
        //root->val = rootValue;
        //root->left = root->right = NULL;
        
        //判断是不是只有一个根节点
        if (startPre == endPre){
            if (startIn == endIn && *startIn == *startPre) return root;
            //else throw std::exception("Invalid input.");
        }
        
        //在中序遍历中找到根节点值的位置
        int* rootIn = startIn;
        while (rootIn <= endIn && *rootIn != rootValue) ++rootIn;
        //if (rootIn == endIn+1 && *rootIn != rootValue) throw std::exception("Invalid input.");
        
        //找到左子树长度
        int leftlength = rootIn - startIn;
        //前序遍历中左子树的结束位置
        int* leftPreend = startPre + leftlength;
        
        if (leftlength > 0){
            //构建左子树
            root->left = ConstructCore(startPre+1,leftPreend, startIn, rootIn-1);
        }
        if (leftlength < endPre - startPre){
            //构建右子树
            root->right = ConstructCore(leftPreend+1, endPre, rootIn+1, endIn);
        }
    }
    
    
    TreeNode* reConstructBinaryTree(int* pre, int* vin, int length) {
        if (pre == nullptr || vim == nullptr || length == 0) return nullptr;
        return ConstructCore(pre, pre+length-1, vin, vin+length-1);
    }

vector用法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) {
        int n1 = pre.size();
        int n2 = vin.size();
 
        if (n1 != n2 || 0 == n1 || 0 == n2) {
            return NULL;
        }
 
        return __buildTree(pre, 0, n1 - 1, vin, 0, n2 - 1);
    }
 
    TreeNode* __buildTree(vector<int>& preorder, int pre_start, int pre_end, vector<int>& inorder, int in_start, int in_end) {
        if (pre_start > pre_end) {
            return NULL;
        }
        //创建根节点
        TreeNode* root = new TreeNode(preorder[pre_start]);
        
        //找到根节点在中序遍历序列中的位置,求得左子树长度
        int length = 0;
        for (int i = in_start; i != in_end; ++i) {
            if (preorder[pre_start] == inorder[i]) {
                break;
            }
            ++length;
        }
 
        if (length > 0) { // 左子树存在,递归左子树
            root->left = __buildTree(preorder, pre_start + 1, pre_start + length, inorder, in_start, in_start + length - 1);
        }
        if (pre_start + length < pre_end) {
            root->right = __buildTree(preorder, pre_start + length + 1, pre_end, inorder, in_start + length + 1, in_end);
        }
        return root;
    }

};

vector方法2:

/**
 
     * Definition for binary tree
 
     * struct TreeNode {
 
     *     int val;
 
     *     TreeNode *left;
 
     *     TreeNode *right;
 
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 
     * };
 
     */
 
    class Solution {
 
    public:
 
        struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
 
            int inlen=in.size();
 
            if(inlen==0)
 
                return NULL;
 
            vector<int> left_pre,right_pre,left_in,right_in;
 
            //创建根节点,根节点肯定是前序遍历的第一个数
 
            TreeNode* head=new TreeNode(pre[0]);
 
            //找到中序遍历根节点所在位置,存放于变量gen中
 
            int gen=0;
 
            for(int i=0;i<inlen;i++)
 
            {
 
                if (in[i]==pre[0])
 
                {
 
                    gen=i;
 
                    break;
 
                }
 
            }
 
            //对于中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边
 
            //利用上述这点,对二叉树节点进行归并
 
            for(int i=0;i<gen;i++)
 
            {
 
                left_in.push_back(in[i]);
 
                left_pre.push_back(pre[i+1]);//前序第一个为根节点
 
            }
 
            for(int i=gen+1;i<inlen;i++)
 
            {
 
                right_in.push_back(in[i]);
 
                right_pre.push_back(pre[i]);
 
            }
 
            //和shell排序的思想类似,取出前序和中序遍历根节点左边和右边的子树
 
            //递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点
 
           head->left=reConstructBinaryTree(left_pre,left_in);
 
           head->right=reConstructBinaryTree(right_pre,right_in);
 
           return head;
 
        }
 
    };
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值