引言
二叉树的遍历大体分为两种,深度优先和广度优先,深度优先分为前中后序三种遍历方法,广度优先就是层序遍历;
我们都知道深度优先遍历是通过栈实现的,广度优先遍历是通过递归实现的;
这里分别用递归和迭代实现一下二叉树的三种深度优先遍历;
注:递归实现比较简单,就只列出核心部分
前序遍历
遍历顺序:中——左——右
递归实现:
void preTraversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
vec.push_back(cur->val); // 中
preTraversal(cur->left, vec); // 左
preTraversal(cur->right, vec); // 右
}
迭代实现:
这里需要注意一下左节点和右节点入栈的顺序,中间节点遍历除栈后,下一个遍历的就该是左节点,但是栈是先进后出,所以应该先让右节点入栈,然后左节点再入栈,这样就是左节点先遍历最后才是右节点;
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> sta;
vector<int> result;
if (root == NULL) return result;
sta.push(root);
while (!sta.empty()) {
TreeNode* node = sta.top(); // 中
sta.pop();
result.push_back(node->val);
if (node->right) sta.push(node->right); // 右(空节点不入栈)
if (node->left) sta.push(node->left); // 左(空节点不入栈)
}
return result;
}
};
中序遍历
遍历顺序:左——中——右
递归实现:
void midTraversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
midTraversal(cur->left, vec); // 左
vec.push_back(cur->val); // 中
midTraversal(cur->right, vec); // 右
}
迭代实现:
中序实现和前序有些不同,先把根节点入栈,然后需要用一个指针一直遍历到左子树的最后一个节点,然后再依次出栈,再遍历右子树;
可以理解为指针帮忙访问节点,栈用来处理节点元素;
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> sta;
TreeNode* cur = root;
while (cur != NULL || !sta.empty()) {
if (cur != NULL) { // 指针来访问节点,访问到最底层
st.push(cur); // 将访问的节点放进栈
cur = cur->left; // 左
}
else {
cur = sta.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
sta.pop();
result.push_back(cur->val); // 中
cur = cur->right; // 右
}
}
return result;
}
};
后序遍历
递归实现:
遍历顺序:左——右——中
void postTraversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
postTraversal(cur->left, vec); // 左
postTraversal(cur->right, vec); // 右
vec.push_back(cur->val); // 中
}
迭代实现:
后序遍历其实和前序遍历很像,后序只需要把前序遍历中左右子树遍历顺序改一下,然后反转结果就可以了;
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> sta;
vector<int> result;
if (root == NULL) return result;
sta.push(root);
while (!st.empty()) {
TreeNode* node = sta.top();
sta.pop();
result.push_back(node->val);
if (node->left) sta.push(node->left);
if (node->right) sta.push(node->right);
}
reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
return result;
}
};
总结
这几种遍历方法在二叉树中经常出现,而且也是二叉树的基础;我经常见到的还是递归,但是迭代也是需要掌握的,有的题目可能会有强制的要求;