二叉树的遍历和二叉树的重建是二叉树重点一个经典问题, 同时也是各大赛事的常考内容(尤其是PAT和天梯赛), 下面我将结合我自己的学习心得和刷题经验简单谈一下二叉树的遍历和重建
二叉树的遍历通常情况下有三种, 分别是前序, 中序, 和后序遍历. 切记, 这里的前, 中, 后值得是根节点的位置, 根节点在前就为前序遍历…以此类推
如图
仔细观察一下, 不难得出一点经验, 其实从代码的层面来看的话, 仅仅是输出语句的位置不同而已
来看一道题吧
请根据以下算法编写一个程序,系统的访问给定二叉树的所有节点。 1.按照根节点,左子树,右子树,的顺序输出节点编号。这称为树的前序遍历。 2.按照左子树,根节点,右子树的顺序输出节点编号。这称为二叉树的中序遍历。 3.按照左子树,右子树,根节点的顺序输出节点编号。这称为二叉树的后序遍历。 设给定二叉树拥有n个节点,编号分别为0至n-1.
第一行输入节点的个数n。接下来n行按照下述格式输入个节点的信息,每个节点占1行。 id left right id 为节点的编号,left 为左子节点编号,right为右子节点编号。不存在子节点是 left(right)为-1。
第一行输出“Preorder”,第二行按前序遍历的前序顺序输出节点编号。 第三行输出“Inorder",第四行按中序遍历的顺序输出节点编号。 第五行输出“Postorder”,第六行按后序遍历顺序输出节点编号。 节点编号前输出1个空格。
Sample Input 1
9
0 1 4
1 2 3
2 -1 -1
3 -1 -1
4 5 8
5 6 7
6 -1 -1
7 -1 -1
8 -1 -1
Sample Output 1
Preorder
0 1 2 3 4 5 6 7 8
Inorder
2 1 3 0 6 5 7 4 8
Postorder
2 3 1 6 7 5 8 4 0
1 ≤ n ≤ 25
给出二叉树的各个节点信息(id, 左, 右), 依次输出前序, 中序, 后序的遍历结果
#include
#include
#include
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int NIL = -1;
const LL maxn = 1e4;
struct node{int p, l, r;}T[maxn];
void preOrder(int n){
if(n==NIL) return;
printf(" %d",n);
preOrder(T[n].l);
preOrder(T[n].r);
}
void inOrder(int n){
if(n==NIL) return;
inOrder(T[n].l);
printf(" %d",n);
inOrder(T[n].r);
}
void PostOrder(int n){
if(n==NIL) return;
PostOrder(T[n].l);
PostOrder(T[n].r);
printf(" %d",n);
}
int main()
{
int N, v, l, r, root;
scanf("%d",&N);
for(int i = 0; i <= N; i++) T[i].p=NIL;
for(int i = 0; i < N; i++){
scanf("%d%d%d",&v,&l,&r);
T[v].l = l, T[v].r = r;
if(l!=NIL) T[l].p = v;
if(r!=NIL) T[r].p = v;
}
for(int i = 0; i < N; i++)
if(T[i].p==NIL)
root = i;
printf("Preorder\n");
preOrder(root);
printf("\nInorder\n");
inOrder(root);
printf("\nPostorder\n");
PostOrder(root);
printf("\n");
return 0;
}
二叉树的重建也是一种极其常见的类型, 通常来说是给出二叉树的前序和中序遍历求后序, 或者给出中序和后序遍历求前序(但不会给出前序后序求中序, 因为无法完成)
这种思维略有巧妙, 如果暂时理解不了的同学也可以记一下模板, 非常常用.
例如给出前序遍历pre = {1,2,3,4,5}, 中序遍历in = {3,2,4,1,5}
我们一次遍历pre, 对于每一个prei, 我们找其在中序遍历中的下标, 那么可以肯定, 该下标左边一定是左子树, 该下标右边一定是该点的右子树, 利用这个原理, 依次递归即可.
模板如下
int N, pre[maxn], in[maxn], post[maxn];
int postPos = 1, prePos = 1;
void rec(int l, int r){
if(l >= r) return;
//pre的下一个节点
int c = pre[prePos++], m;
//c在in中的位置
for(int i = 1; i <= N; i++)
if(in[i] == c){
m = i; break;
}
rec(l, m); //重建左子树
rec(m+1, r);//重建右子树
post[postPos++] = c;
}
同理可得, 给出中序和后序求前序遍历, 从后往前遍历post, 同时输出顺序也要改变
int N, pre[maxn], in[maxn], post[maxn];
int postPos = N, prePos = 1;
void rec(int l, int r){
if(l >= r) return;
//post的下一个节点
int c = post[postPos--], m = 0;
//c在in中的位置
for(int i = 1; i <= N; i++)
if(in[i] == c){
m = i; break;
}
rec(m+1, r);//重建右子树
rec(l, m); //重建左子树
pre[prePos++] = c;
}
来看一道例题吧
Write a program which reads two sequences of nodes obtained by the preorder tree walk and the inorder tree walk on a binary tree respectively, and prints a sequence of the nodes obtained by the postorder tree walk on the binary tree.
In the first line, an integer n, which is the number of nodes in the binary tree, is given.
In the second line, the sequence of node IDs obtained by the preorder tree walk is given separated by space characters.
In the second line, the sequence of node IDs obtained by the inorder tree walk is given separated by space characters.
Every node has a unique ID from 1 to n. Note that the root does not always correspond to 1.
Print the sequence of node IDs obtained by the postorder tree walk in a line. Put a single space character between adjacent IDs.
Sample Input 1
5
1 2 3 4 5
3 2 4 1 5
Sample Output 1
3 4 2 5 1
Sample Input 2
4
1 2 3 4
1 2 3 4
Sample Output 2
4 3 2 1
1≤n≤40
给出N个节点树的前序和中序遍历, 求后序遍历
直接套模板即可, 但切记N要略大一点
#include
#include
#include
#include
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int inf = 1<<30;
const LL maxn = 45;
int N, pre[maxn], in[maxn], post[maxn];
int postPos = 1, prePos = 1;
void rec(int l, int r){
if(l >= r) return;
//pre的下一个节点
int c = pre[prePos++], m;
//c在in中的位置
for(int i = 1; i <= N; i++)
if(in[i] == c){
m = i; break;
}
rec(l, m); //重建左子树
rec(m+1, r);//重建右子树
post[postPos++] = c;
}
int main()
{
cin >> N;
for(int i = 1; i <= N; i++)
cin >> pre[i];
for(int i = 1; i <= N; i++)
cin >> in[i];
rec(1, N+1);//右边界要略大一点
cout << post[1];
for(int i = 2 ; i <= N; i++)
cout << " " << post[i];
cout << endl;
return 0;
}
参考博客: https://blog.csdn.net/CSDN___CSDN/article/details/86529365