二叉树的遍历时非常经典的考题,主要有前序、中序、后序三种,但是我对这具体怎么遍历还是有点混乱,这里写一篇文章理一下:
以下面的这个二叉树为例:
相对应地建起树:
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#define linkNum 3
const int MAXN = 2e5 + 7;
using namespace std;
typedef struct node {
int left, right;
}NODE;
NODE t[MAXN];
int main() {
t[3].left = 2;
t[3].right = 7;
t[2].left = 1;
t[2].right = 4;
t[7].left = 8;
t[4].left = 5;
t[4].right = 6;
return 0;
}
1、前序:先根节点,然后左子树,然后右子树
void pre_order(int x) {
printf("%d\n", x);
if (t[x].left) pre_order(t[x].left);
if (t[x].right) pre_order(t[x].right);
}
运行一下试试的结果:
这个应该很好理解,从左一路遍历到底,然后从最深的地方找右子树
2、中序:先左子树,再根结点,再右子树
void in_order(int x) {
if (t[x].left) in_order(t[x].left);
printf("%d\n", x);
if (t[x].right) in_order(t[x].right);
}
运行结果:
其实一开始看到这个结果我是有点懵的,1,2后面为什么不是4而是5 4 6呢?后来发现可以这么理解:类比于递归的思想,546那个整个分支看成右子树的一个节点,然后在对整个部分进行中序读数,看图理解下:
3、后序遍历:先左子树再右子树,最后根节点
void post_order(int x) {
if (t[x].left) post_order(t[x].left);
if (t[x].right) post_order(t[x].right);
printf("%d\n", x);
}
这个结果同理~和刚才的中序可以对比一下
4、关于三种遍历方法的总结:
void pre_order(int x) {
printf("%d\n", x);
if (t[x].left) pre_order(t[x].left);
if (t[x].right) pre_order(t[x].right);
}
void in_order(int x) {
if (t[x].left) in_order(t[x].left);
printf("%d\n", x);
if (t[x].right) in_order(t[x].right);
}
void post_order(int x) {
if (t[x].left) post_order(t[x].left);
if (t[x].right) post_order(t[x].right);
printf("%d\n", x);
}
把三段代码放在一起可以看出来其实基本结构没有变化,只是printf的位置变了,从而影响到跟节点的输出位置。
拓展思考:
就在我写上一段文字的时候脑洞大开,既然是3种位置,不应该有A33=6种排列组合方式吗?但是printf三个位置都放过了啊?剩下的方式呢?
一看上面其实是多了另一重约束在的:左子树在右子树前面输出,即为A33/A22 = 3种了,么得任何问题~
番外:关于几种遍历方式相互转换的问题,洛谷P1827是其中的一种情况,大家感兴趣的话可以看看我的另一篇博客~
传送门: