二叉树遍历的循序
先序遍历:[根 [左子树先序遍历结果] [右子树先序遍历结果]]
中序遍历:[[左子树中序遍历结果] 根 [右子树中序遍历结果]]
后序遍历:[[左子树后序遍历结果] [右子树后序遍历结果] 根]
已知前序和中序,构造二叉树
在中序遍历中,根结点的左边所有结点构成了这个根的左子树,右边所有结点构成了这个根的右子树。
只要在中序遍历中找到根结点的位置,就能确定左子树和右子树的结点数目。在先序遍历和中序遍历中分别对左右子树进行定位,递归构造出左子树和右子树,再将这两棵子树连接到根结点上。
首先确定根结点:前序遍历的第一个就是根节点,
在中序遍历中找到根结点,(对左右子树的结点所在前序遍历和中序遍历区间进行定位)
建立左子树,建立右子树,
至于如何建立左右子树,请重新再读一遍这段话。
假设结点的值互不相同,于是建立一个映射indx,直接在中序遍历中找到根的位置(当然也可以直接for循环遍历一遍中序遍历 ,找到 根 的位置)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<unordered_map>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 7;
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x): val(x), left(NULL), right(NULL){}
};
int n, pre_order[MAXN], in_order[MAXN];
unordered_map<int, int> indx;
// [l1, r1]是先序遍历的区间, [l2, r2]是中序遍历的区间
TreeNode* build(int l1, int r1, int l2, int r2)
{
if(l1 > r1) return nullptr;
int p_root = pre_order[l1]; // 找到先序遍历中根结点的位置
int i_root = indx[p_root]; // 在中序遍历中找到根结点的位置
TreeNode* root = new TreeNode(p_root); // 建立根结点
int len = i_root - l2; /// 结点root的左子树长度
root->left = build(l1 + 1, l1 + len, l2, i_root - 1);
root->right = build(l1 + len + 1, r1, i_root + 1, r2);
return root;
}
void print(TreeNode* root) // 输出二叉树的后序遍历
{
if(!root) return ;
print(root->left);
print(root->right);
cout << (root->val) << " ";
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++) cin >> pre_order[i];
for(int i = 0; i < n; i++) {cin >> in_order[i]; indx[in_order[i]] = i; }
TreeNode* ans = build(0, n - 1, 0, n - 1);
print(ans);
return 0;
}
/*
pre_order: 1 2 3 4
in_order: 2 1 4 3
post_order: 2 4 3 1
*/
复杂度
- 时间复杂度:O(n), n是树中结点数
- 空间复杂度:O(n),构造树需要O(n)空间,还需要O(n)进行哈希存储,以及O(h)(h为树的高度)的空间表示递归时栈空间,此处O(h) < O(n), 所以总空间复杂度为O(n)