Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
postorder :n. [计] 后根次序;后缀次序
postorder traversal of a tree:后序遍历的树
construct :构建
binary tree:二叉树
assume :vi. 设想;承担;采取
duplicates :n. 副本,[印刷] 复制品(duplicate的复数形式);多重记录;倍增
duplicates do not exist in the tree:树中没有重复的元素
题意:
给你一个中序和后序遍历的树,请你构建二叉树,你可以认为树中没有重复的元素,
先用题意来算一次:
inorder = [9,3,15,20,7] 左根右
postorder = [9,15,7,20,3]左右根
那么 根据后序遍历最后一个数是根,那么3为根,9和15,20,7就是这个的左右子树
再分别遍历左右子树,左子树只有9,所以就是他,
右子树中分别是中15,20,7
柚子树的后序遍历15,7,20;
根据后序遍历可知20为根在根据中序遍历子树可以知道15为左7为右
就是用这种方法写的,然后我们可以找到跟多的节点的树的情况,但是怎么把我们这个思想用程序实现呢?
明显的我们应该用递归,然后根据后序遍历来找第一个根节点然后放入队列中,然后可以找到左子树的根节点放入队列中,右子树的根节点放入队列中然后依次递归下去(如果遇到节点是空的就让他和他的上个元素相同,然后我们只输出第一次出现的元素),当到他的时候我们就输出空格.
但是怎么看他的左子树是不是空的呢,就看他左边有没有元素(就是在他的范围内有没有越界,如果在他的范围内左边有元素就说明有元素)
ok fine 去试试对不对.
/**
* 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 {
private:
TreeNode *Root;
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
//处理中序和后序的元素:
Root = new TreeNode();
int insize = inorder.size();
int posize = insize;
//通过后序找到根,在到中序中找到左右子树
// cout<<1<
if(insize>0)
{
// Root.val = postorder[insize-1];
// cout<<2<
find(0 , insize,insize-1, Root,inorder,postorder);
}
else if(insize==0) return NULL;
// cout<<7<
return Root;
}
void find( int instart ,int size ,int postend ,TreeNode *root,vector<int>& inorder, vector<int>& postorder )//中序遍历开始的地方,数据的个数,后序遍历结束的位置
{
//找到根
cout<<"当前树中序开始的位置和后序结束的位置:"<<instart <<" "<<size<<" " <<postend <<" "<<endl;
if(size ==0) return ;
root->val = postorder[postend];
cout<<"加入的元素"<<root->val<<endl;
if(size <=1||postend<0) return ;
cout<<root->val<<endl;
//找到左右子树并加入
int temp = instart;
cout<<"在找之前的temp"<<temp<<endl;
while(temp <=instart+size-1)
{
//找到根在中序的位置
if(inorder[temp]!=root->val) temp++;
else if(inorder[temp]==root->val) break;
}
//将左右子树进行递归
//找到中序遍历中左右子树的大小:
cout<<"在左子树中的位置"<<temp<<endl;
int leftsize = temp - instart;
int rightsize = size -leftsize-1;
cout<<"左右子树的个数:"<<leftsize<<" "<<rightsize<<" "<<endl;
//在后序遍历中找到左右子树
//先找右子树的结束的点:
int postleftend = postend -rightsize-1;//后序遍历的左子树的结束位置
int rightpostend = postend -1;//后序遍历右子树的结束位置
// cout<<4<
TreeNode *leftroot = new TreeNode();
TreeNode *rightroot = new TreeNode();
cout<<"后序遍历中两个子树开始的位置:(从最后一个开始)"<<postleftend <<" "<<rightpostend<<" "<<endl;
//遍历左子树
root->left = leftroot;
// cout<<5<
cout<<" 进入他的左子树"<<endl;
find(instart ,leftsize , postleftend ,leftroot ,inorder ,postorder);
//遍历右子树
// cout<<5<
//cout<
if(rightsize>0)
{
root->right = rightroot;
cout<<"进入他的右子树:"<<endl;
find(temp+1 ,rightsize , rightpostend ,rightroot ,inorder ,postorder ) ;
}
// cout<<6<
}
};
1:需要注意的是返回值是treenode * ,不能用treenode r,&r 实现,
2:在判断他的左右子有没有元素前不能将他的地址加到上个节点上,因为会给你默认赋值0;
3:逻辑思路要清晰,不能乱
整体思路就是先通过后序遍历找到他的根,在到中序遍历中去找根的位置,然后分成左右两个子树,找到左右子树的大小,然后再在后序遍历中找到左右子树,在分别找到左右子树在后序遍历中找到的结束的位置,然后再分别遍历左右子树,但是中间的细节也很重要哦,比如在不知道左右子树存不存在的时候就先不能把他的左右子树加到上个节点的根上.