重建二叉树的思路

来源:互联网 发布:kmp算法next数组程序 编辑:程序博客网 时间:2024/05/22 08:31

用LRM分别表示节点的左孩子、右孩子、节点本身,

用cur表示当前正在讨论的节点,

用ABC分别表示前序遍历(MLR)、中序遍历(LMR)、后序遍历(LRM)的三个数组。


①已知AB

<1> 可以确定,A[0]是根节点,令cur=A[0]。

<2> 如果B[0]≠cur:

可以确定,cur有左孩子,因为在B中,只有cur的左子树里的节点会出现在cur所在位置之前,

可以确定,在A中,cur之后的那个元素就是cur的左孩子,因为直系的父亲和左孩子肯定是挨着的(由定义),cur=这个左孩子。


如果B[0]=cur:

可以确定,cur没有左孩子,或者左孩子已经安排好已经从B中删除了,接下来考虑cur的右孩子

删除B[0],因为B[0]的作用是充当我们区分左孩子和右孩子的界限——父节点,也就是现在的cur,现在已经只剩下右孩子需要讨论,所以B[0]的使命已经完成。

<3> 如果<2>中属于有左孩子的情况,就继续按照<2>的判断条件确定当前的cur有没有左孩子。

如果<2>中确定没有左孩子,讨论右孩子:

如果B[0]≠cur的父节点或者cur没有父节点了:

可以确定,cur有右孩子,因为如果cur没有右孩子,在B中,cur后面紧跟着的就应该是cur的父节点或者结束。

可以确定cur的右孩子就是A中cur的后一个元素,因为此时已知cur没有左孩子、有右孩子,所以cur紧挨着的肯定是右孩子,cur=右孩子。


如果B[0]=cur的父节点,可以确定cur没有右孩子,cur=cur的父节点,继续按照<3>中对右孩子讨论的方法进行判断。

<4> 如果B数组空,即所有节点都已经判断完毕,A中的所有元素都已经有了自己的位置,重建结束。


举个例子:


1:A[0]=a是根节点,cur=a

2:B[0]=b,cur≠b,所以a的左孩子是A[1]=b,cur=b

3:B[0]=b,cur=b,所以b没有左孩子,删除B[0]

4:B[0]=a,cur的父节点=a,所以b没有右孩子,cur=a,删除B[0]

5:B[0]=d,cur≠d,所以a有右孩子,是A[2]=c,cur=c

6:B[0]=d,cur≠d,所以c有左孩子,是A[3]=d,cur=d

7:B[0]=d,cur=d,所以d没有左孩子,删除B[0]

8:B空,重建结束


C++实现:

struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}};

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {if(pre.size() == 0)return NULL;TreeNode *p;TreeNode *root;stack<TreeNode *> stn;root = new TreeNode(pre[0]); stn.push(root); pre.erase(pre.begin());while(true){if(vin[0] == stn.top()->val)//没有左孩子,或者左孩子已经安排好了,这里的栈顶元素就相当于cur{p = stn.top();//讨论右孩子,暂时把讨论节点保存到p,出栈,从而得到该节点的父节点,即此时的栈顶stn.pop(); vin.erase(vin.begin());if(vin.size() == 0) break;if(stn.size() && vin[0] == stn.top()->val)//没有右孩子continue;p->right = new TreeNode(pre[0]); pre.erase(pre.begin());stn.push(p->right);}else {p = new TreeNode(pre[0]);pre.erase(pre.begin());stn.top()->left = p; stn.push(p); }}return root;}

②已知BC

类比①,首先,C的最后一个元素是根节点

然后判断B的最后一个元素和该节点值是否相等,若不相等说明有右孩子;若相等就考虑其左孩子,删掉B的最末元素,然后判断B的最后一个元素和当前节点的父节点是否相等,如果不相等或者当前节点没有父节点,说明当前节点有左孩子,否则说明没有左孩子,继续讨论这个父节点,直到所有元素均找到自己的位置。

C++实现:

TreeNode* buildTree(vector<int>& vin, vector<int>& post) {if(vin.size() == 0)return NULL;TreeNode *p;TreeNode *root;stack<TreeNode *> stn;root = new TreeNode(post.back()); stn.push(root); post.pop_back();while(true){if(vin.back() == stn.top()->val){p = stn.top();stn.pop(); vin.pop_back(); if(vin.size() == 0) break;if(stn.size() && vin.back() == stn.top()->val)continue;p->left = new TreeNode(post.back()); post.pop_back();stn.push(p->left);}else {p = new TreeNode(post.back());post.pop_back();stn.top()->right = p; stn.push(p); }}return root;}


③已知AC


可以看出这两个二叉树的前序遍历和后序遍历是一样的。因为当只存在左或右一个孩子的时候,前序和后序遍历是无法分辨到底是左还是右的。



原创粉丝点击