C++ 已知二叉树两种遍历序列,构建二叉树
- 已知先序遍历和中序遍历,可以求出后序遍历
- 已知后序遍历和中序遍历,可以求出先序遍历
- 已知先序遍历和后序遍历,不可求出中序遍历
1.已知先序遍历和中序遍历,求后序遍历
1.1 解题思想:
由先序遍历的特点可知,先序遍历第一个元素为二叉树的根。由中序遍历的特点可知,二叉树的根的左面为左子树的中序遍历,右面为右子树的中序遍历。由先序遍历可以知道二叉树的根,由中序遍历可以知道二叉树的左子树和右子树,因此,我们可以用递归的思想,将整个二叉树递归分解成左子树和右子树,直到子树为空为止。
1.2 实现细节:
已知先序遍历是先遍历当前二叉树的根,然后递归遍历左子树和右子树。再由中序遍历根的位置可以得出左子树和右子树的长度(大小)。再将左右子树的长度带入先序遍历,就可以得出左子树的先序遍历和右子树的先序遍历,结合左右子树的中序遍历,就可以递归求解。
1.3 参考代码:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector <char > post;
string pre, mid;
void solve(int l1, int r1, int l2, int r2)
{
if(r1 < l1)
return ;
post.push_back(pre[l1]);//将根按顺序存在数组里
int q = l2;
while(pre[l1] != mid[q]) q++;//在中序中找到根
int cnt = q - l2;//左子树元素个数
//先遍历右子树在遍历左子树,这样就可以按照 根、右、左顺序存在容器中,倒序输出即为答案
solve(l1 + cnt+1, r1, q+1, r2);//递归右子树
solve(l1+1, l1+cnt, l2, q-1);//递归左子树
}
int main()
{
while(cin >> pre >> mid)
{
post.clear();
solve(0, pre.size()-1, 0, mid.size()-1);
//倒序输出
for(int i = post.size() - 1; i >= 0; i--)
{
cout << post[i];
}
cout << endl;
}
return 0;
}
2.已知后序遍历和中序遍历,求先序遍历
2.1解题思想:
总体思想和用先序、中序求后序相同。后序遍历是先遍历左右子树,最后才是根。因此,后序遍历最后一个元素是二叉树的根。在中序遍历找到根的位置,根的左面就是左子树的中序遍历,右边就是右子树的先序遍历,根据其长度,将后序遍历分成左右子树的后序遍历。
2.2 实现细节:
假设中序遍历中,根的左面有lenA个元素,右边有lenB个元素,那么就可以知道其左子树有lenA个元素,右子树有lenB个子树。由后序遍历的特点可知,最后一个元素为根,根的前面lenB个元素为右子树的后序遍历,在这些元素前面的lenA个元素为左子树的后序遍历,因此可以递归求解。
2.3 代码实例:
#include<iostream>
#include<string>
using namespace std;
string mid,post;
string ans;
void solve(int l1,int r1,int l2,int r2){
if(r1 < l1) return;
int p = l2;
ans+=post[r1];
while(post[r1] != mid[p]) p++;
int len = p - l2;
solve(l1,r1-len-1,l2,l2+len-1);
solve(r1-len,r1-1,l2+len+1,r2);
}
int main()
{
while(cin >> post >> mid){
solve(0,post.length()-1,0,mid.length()-1);
cout << ans << endl;
}
return 0;
}