树的遍历¶
普通树¶
深度优先¶
对于一个结点,遍历完我们优先拓展深度。一般采用递归或栈来实现。例如,以下图的深度优先遍历顺序为:\(1-2-5-4-3-6\)。
void dfs(int x) {
cout << x << ' ';
for (int i : e[x]) {
dfs(x);
}
}
void dfs(int x) {
stack<int> s;
for (s.push(x); s.size(); ) {
int t = s.top();
s.pop();
for (int i : e[x]) {
s.push(i); // 注意这里遍历儿子的顺序是反的
}
}
}
广度优先¶
也称层序遍历。每一次都遍历一整层,一般使用队列实现。例如上图的广度优先遍历的顺序为:\(1-2-3-5-4-6\)。
void bfs(int x) {
queue<int> q;
for (q.push(x); q.size(); q.pop()) {
cout << q.front() << ' ';
for (int i : e[q.front()]) {
q.push(i);
}
}
}
对于无根树¶
由于没有指定的根,因此我们在存储时也不知道谁是谁的什么,那么我们只能双向存储。因此在遍历时,我们需要记录一个结点的前继是谁,然后在遍历儿子的时候去掉这个前继。
void dfs(int x, int f) {
cout << x << ' ';
for (int i : e[x]) {
if (i != f) {
dfs(i, x);
}
}
}
void bfs(int x, int f) {
queue<pair<int, int>> q;
for (q.emplace(x, f); q.size(); q.pop()) {
cout << q.front().first << ' ';
for (int i : e[q.front().first]) {
if (i != q.front().second) {
q.emplace(i, q.front().first);
}
}
}
}
二叉树¶
先序遍历¶
先遍历根结点,然后遍历左子树,接着遍历右子树。通俗一点讲就是“根左右”。最上面我给的图就是一颗二叉树,先序遍历顺序为:\(1-2-5-4-3-6\)。
void dfs(int x) {
cout << x << ' ';
if (t[x].l) {
dfs(t[x].l);
}
if (t[x].r) {
dfs(t[x].r);
}
}
中序遍历¶
先遍历左子树,再遍历根结点,最后遍历右子树。通俗一点讲就是“左根右”。上图中序遍历顺序为:\(5-2-4-1-3-6\)。
void dfs(int x) {
if (t[x].l) {
dfs(t[x].l);
}
cout << x << ' ';
if (t[x].r) {
dfs(t[x].r);
}
}
后序遍历¶
先遍历左子树,再遍历右子树,最后遍历根结点。通俗一点讲就是“左右根”。上图中序遍历顺序为:\(5-4-2-6-3-1\)。
void dfs(int x) {
if (t[x].l) {
dfs(t[x].l);
}
cout << x << ' ';
if (t[x].r) {
dfs(t[x].r);
}
}