Inorder , Postorder and Preorder Traversal to Construct Binary

不管是由先序遍历+中序遍历构造二叉树,还是由后序遍历+中序遍历构造二叉树,其实关键在于中序遍历,正是由于它的存在才使得构造出的二叉树唯一性,换句话说,由先序遍历+后序遍历得到的二叉树是不唯一的。

为什么呢?因为一个二叉树最基本的单元就是根节点+左右子树,再庞大的二叉树也都是由其不断递归组成即可:

根节点:先序遍历和后序遍历都能准确的找到根节点

左右子树:中序遍历很容易找到根节点的左右子树

 可以看到先序遍历和后序遍历只要有一个即可,因为两种都能找到根节点,可以彼此替代,无非就是一个从前到后,一个从后到前,但左右子树的获得只能使用中序遍历这一种方法,别无他选!!!!!!!!!!!!!!!!

明白了上面的逻辑我们就来具体看看怎么构建树吧。

我们首先来看看怎么由后序遍历+中序遍历来重构我们的二叉树。

很明显postorder最后一个数就是根节点即3

然后我们就将inorder中以3为分界线,左面就是3这个更节点的左子树,右面就是3这个根节点的右子树,接下来就是分别在左子树和右子树中通过postorder找到自己对应下的根节点(就是对应序列中的最后一个元素),不断重复上面这一过程。

其实难点在于怎么在postorder找到对应子区间。

先给出代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    map<int,int>m;
    TreeNode*Helper(vector<int>& inorder, vector<int>& postorder,int first, int end,int pos,int cur){
        TreeNode*result = new TreeNode(postorder[cur]);
        int temp = m[postorder[cur]];
        if(temp>first) result->left = Helper(inorder,postorder,first,temp-1,pos,pos+temp-first-1);
        if(temp<end)   result->right = Helper(inorder,postorder,temp+1,end,pos+temp-first,cur-1);
        return result;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.empty()) return NULL;
        int length=inorder.size();
        for(int i=0;i<length;i++){
            m.insert(pair<int,int>(inorder[i],i));
        }
        return Helper(inorder,postorder,0,length-1,0,length-1);
    }
};

first和end就是代表子树的区间,主要应用在inorder中,pos和cur主要应用在postorder中,找到对应的子区间

temp-first就是当前根节点左子树的长度,所以在假设当前根节点的n,那么其左子树体现在postorder数组中的下标一定就是pos~pos+temp-first-1,下一个区间的根节点就是最后一个数即pos+temp-first-1,为什么呢?

因为在postorder中是这样:假设我们在inorder中找到root的左子树是5个元素,那么其在postorder数组中体现的就是在root前面的元素一共就有5个元素,因为postorder就是先左再右后自己,下面图很好的体现了他们的关系

右子树就是起第一个开始是pos+temp-first,最后一个数就是cur-1.

然后就是递归即可。

可能有人会对pos存在感到疑惑,左子树的最后一个不就是temp-1嘛!为什么要弄出个pos,这么麻烦。

我们看一下题目给出的例子:

假设当前我们递归到【15,20,7】这棵子树,根节点是20,小标是3,那么3-1=2按说是其右子树的更节点但是postorder[2]是7,显然错误,倘若这样看又是对的

其实这就是相对与绝对的问题,代码中采用的就是相对的方法,pos起点+temp-first子树长度就是当前根节点右子树的相对起点。

再来看看怎么由前序遍历+中序遍历来重构我们的二叉树。

同理还是定义first和end在Inorder上面找到根节点的左右子树,根节点呢?就是在最前面了:

class Solution {
public:
    map<int,int>M;
    int j;
    TreeNode*Helper(vector<int>& preorder, vector<int>& inorder,int first,int end,int &i){
        TreeNode *temp = new TreeNode(preorder[i]);
        int medier = M[preorder[i]];
        if(medier>first){     
            temp->left = Helper(preorder,inorder,first,medier-1,++i); 
        }
        if(medier<end){
            temp->right = Helper(preorder,inorder,medier+1,end,++i);
        }
        return temp;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()){
            return NULL;
        }
        int length = preorder.size();
        for(int i=0;i<length;i++){
            M.insert(pair<int,int>(inorder[i],i));
        }
        j=0;
        TreeNode *result=Helper(preorder,inorder,0,length-1,j);
        return result;
        
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_42001089/article/details/85038529