重建二叉树
1.根据前序遍历和中序遍历构造二叉树:如:前序和中序遍历序列分别为[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6].要构造出如下的二叉树:
思路:1.要构造出二叉树首先的找到根节点,由前序遍历可以知道第一个元素肯定是整个二叉树的根节点;2.然后在中序遍历中找到这个节点所在值,那么就可以确定中序左子树的节点数.3.由上面求出的左子树节点数就可以明确中序左子树范围(这里是序列的下标),中序右子树的范围和前序左子树、前序右子树范围;4.根据前序遍历进行递归从而生成整棵二叉树
实现代码:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode* preorder(int preleft,int preright,int inleft,int inright,vector<int>&pre,vector<int>&vin){
if(preleft>preright||inleft>inright)return NULL; //终止条件
TreeNode* cur=new TreeNode(pre[preleft]);
//先找到根节点
int root=inleft;
while(root<=inright&&vin[root]!=pre[preleft])root++;
//确定中序左子树 和右子树范围
//前序左子树 右子树范围
int left=root-inleft; //左子树个数
//下面进行递归
cur->left=preorder(preleft+1,preleft+left,inleft,root-1,pre,vin);
cur->right=preorder(preleft+left+1,preright,root+1,inright,pre,vin);
return cur;
}
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
return preorder(0,vin.size()-1,0,vin.size()-1,pre,vin);
}
};
**2.**根据后序遍历和中序遍历构造二叉树.如:后序和中序遍历序列分别为 [9,15,7,20,3],[9,3,15,20,7],要构造出如下二叉树:
思路:1.后序遍历的最后一个元素肯定是整棵二叉树根节点,先由后序遍历确定根节点;2.根据根节点在中序遍历序列中找到所对应值,切割成中序左子树和中序右子树;3.然后根据中序左子树大小切割后序序列为后序左子树和后序右子树(注意:切割后序序列时,要把最后一个节点扔掉,因为已经是由后序序列确定了根节点);4.由后序左子树和后序右子树又可以确定上一层中序左子树和右子树的切割点,以此往复递归下去.
流程图示:
实现代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
//递归法
if(inorder.size()==0||postorder.size()==0)return nullptr; //终止条件
//根节点
int root=postorder[postorder.size()-1];
TreeNode* cur=new TreeNode(root);
//找到中序序列中的切割点
int p;
for(p=0;p<inorder.size();p++){
if(inorder[p]==root)break;
}
//切割中序序列
vector<int>in_left(inorder.begin(),inorder.begin()+p); //中序左子树
vector<int>in_right(inorder.begin()+p+1,inorder.end()); //中序右子树
//切割后序序列 并扔掉最后一个元素
vector<int>post_left(postorder.begin(),postorder.begin()+in_left.size()); //后序左子树
vector<int>post_right(postorder.begin()+in_left.size(),postorder.end()-1); //后序右子树
//递归
cur->left=buildTree(in_left,post_left);
cur->right=buildTree(in_right,post_right);
return cur;
}
};
总结:前序和中序遍历,后序和中序遍历都可以唯一确定一棵二叉树,那是因为前序遍历和后序遍历可以明确根节点,从而在中序遍历中能确定切割点,可以知道切割范围.如1中情形,当知道切割点位置就可以知道中序左子树和中序右子树的范围,进而前序左子树和前序右子树范围也随之确定.那么已知前序和后序遍历可以确定唯一的二叉树吗?答案是不能.如下图所示:前序遍历和后序遍历都是[1,2],[2,1],但明显他们是两棵二叉树