二叉树的遍历
前言
二叉树的遍历是二叉树的基础算法,本文对个人的遍历写法做个记录
深度优先遍历
递归写法
递归遍历比较简单,不作讲解和注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 前序遍历
void preorder(Node* node) {
if (node) {
visit(node);
preorder(node->left);
preorder(node->right);
}
}
// 中序遍历
void inorder(Node* node) {
if (node) {
inorder(node->left);
visit(node);
inorder(node->right);
}
}
// 后序遍历
void postorder(Node* node) {
if (node) {
postorder(node->left);
postorder(node->right);
visit(node);
}
}
非递归写法
三种遍历的非递归写法难以统一的原因是在栈的遍历过程中,在处理当前节点时还需要指针去索引另一个访问节点,这里记录一个统一的迭代写法,将两种节点都放入栈中,但是在处理的当前节点后放入一个null与访问节点区分,这种写法在三种遍历上只需要改动顺序
前序遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
vector<Node*> preorder(Node* root) {
vector<Node*> res;
stack<Node*> stack;
if (root) stack.push(root);
while (!stack.empty()) {
// 当前节点
Node* node = stack.top();
// 该节点是访问节点
if (node) {
stack.pop();
// 从左到右,左节点在栈顶,先放入右节点
if (node->right) stack.push(node->right);
if (node->left) stack.push(node->right);
// 前序遍历,根节点在栈顶
stack.push(node);
// 添加null,使访问节点变为处理节点,即下次访问到null,将该节点放入结果集
stack.push(nullptr);
} else {
// 遇到null,则栈顶下一个元素是处理节点
stack.pop();
// 获取处理节点
node = stack.top();
stack.pop();
res.push_back(node);
}
}
return res;
}
中序遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
vector<Node*> inorder(Node* root) {
vector<Node*> res;
stack<Node*> stack;
if (root) stack.push(root);
while (!stack.empty()) {
Node* node = stack.top();
if (node) {
stack.pop();
if (node->right) stack.push(node->right);
if (node->left) stack.push(node->left);
stack.push(node);
stack.push(nullptr);
} else {
stack.pop();
node = stack.top();
stack.pop();
res.push_back(node);
}
}
return res;
}
后序遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
vector<Node*> postorder(Node* root) {
vector<Node*> res;
stack<Node*> stack;
if (root) stack.push(root);
while (!stack.empty()) {
Node* node = stack.top();
if (node) {
stack.pop();
stack.push(node);
stack.push(nullptr);
if (node->right) stack.push(node->right);
if (node->left) stack.push(node->left);
} else {
stack.pop();
node = stack.top();
stack.pop();
res.push_back(node);
}
}
return res;
}
层次遍历
层次遍历写法较简单,要注意它的应用,灵活变化
非递归写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vector<vector<Node*>> levelorder(Node* root) {
queue<Node*> q;
// 每一层是一个vector
vector<vector<Node*>> res;
if (root) q.push(root);
while (!q.empty()) {
// 当前层宽度
int size = q.size();
vector<Node*> level;
for (int i = 0; i < size; i++) {
Node* node = q.front();
q.pop();
level.push_back(node);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
res.push_back(level);
}
return res;
}
递归写法
使用前序遍历,通过深度索引到相应的层数组再添加,根节点的深度为0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void levelorder(Node* node, vector<vector<Node*>>& res, int depth) {
if (!node) return;
// 到达最后一层的下一层时,若还有节点,创建数组
if (res.size() == depth) res.push_back(new vector<Node*>());
res[depth].push_back(node);
levelorder(node->left, res, depth + 1);
levelorder(node->right, res, depth + 1);
}
vector<vector<Node*>> level(Node* root) {
vector<vector<Node*>> res;
levelorder(root, res, 0);
return res;
}
本文由作者按照 CC BY 4.0 进行授权