写在前面
二叉树的遍历方式,基本可以归结为四种:前序遍历、中序遍历、后序遍历、层次遍历
先序遍历顺序:根,左儿子,右儿子
中序遍历顺序:左儿子,根,右儿子
后序遍历顺序:左儿子,右儿子,根
层次遍历顺序:根据每一层的顺序,由左向右依次输出
遍历顺序及转换
先序遍历:4 1 3 2 6 5 7
中序遍历:1 2 3 4 5 6 7
后序遍历:2 3 1 5 7 6 4
层次遍历:4 1 6 3 5 7 2
变换原理:
我们知道中序遍历和先序遍历或者知道中序遍历和后序遍历就可以知道剩余的两种遍历顺序,因为前序遍历在一个区间中,第一个一定是根节点,后序遍历中最后一个一定是根节点,那么这个区间就由中序遍历给出,已知根节点,在中序遍历中找到相应位置,左边数组一定位于左子树,右边数组一定位于右子树中。
已知中序遍历和后续遍历,得到对应的二叉树,实现:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
using namespace std;
const int maxn = 1005;
int in_order[maxn],post_order[maxn];
int n;
int lch[maxn],rch[maxn];
queue<int> que;
int build_tree(int l1,int r1,int l2,int r2)
{
if(l1 > r1) return 0;
int root = post_order[r2]; //当前区间中的根节点
int pos = l1;
while(in_order[pos] != root) pos++; //在中序遍历中找到根节点的位置,将序列分成左右两个区间
int cnt = pos - l1; //左子树区间的长度
printf("%d ",root);
lch[root] = build_tree(l1,pos-1,l2,l2+cnt-1); //遍历左子树
rch[root] = build_tree(pos+1,r1,l2+cnt,r2-1); //遍历右子树
return root;
}
void BFS(int root)
{
que.push(root);
while(!que.empty())
{
int node = que.front();
que.pop();
printf("%d ",node);
if(lch[node]) que.push(lch[node]);
if(rch[node]) que.push(rch[node]);
}
}
int main()
{
scanf("%d",&n);
for(int i = 0;i < n;i ++)
scanf("%d",post_order+i); //后序遍历
for(int i = 0;i < n;i ++)
scanf("%d",in_order+i); //中序遍历
printf("先序遍历:\n");
int root = build_tree(0,n-1,0,n-1);
printf("\n");
printf("层次遍历:\n");
BFS(root);
printf("\n");
}
相对应的前序和中序推后续与上面类似,只是根节点确认以及输出顺序不同。
参考书籍
《算法竞赛入门经典(第二版)》刘汝佳著