二叉树的前中后序遍历是学习树形结构时必须要掌握的算法,同时也是树形结构中最基础的算法,通过前中后序遍历的变形能解决很多二叉树相关的算法问题。前中序后算法的递归版本代码比较简单也很简洁明了,这里不再给出。
下面分别给出前中后序的迭代版本。
先序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> s;
TreeNode *p = root;
while (!s.empty() || p){
// 优先向左,入栈之前先输出
if (p){
res.push_back(p->val);
s.push(p);
p = p->left;
}
else{
// 左子树为空,向右出发
p = s.top()->right;
s.pop();
}
}
return res;
}
};
中序遍历
基本和先序一样,只是输出的时间不同
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if (root == nullptr) return res;
stack<TreeNode*> s;
TreeNode *p = root;
while (!s.empty() || p){
if (p){
s.push(p);
p = p->left;
}
// 其实本质和先序一样,只不过是再弹出栈顶结点时才输出
else{
res.push_back(s.top()->val);
p = s.top()->right;
s.pop();
}
}
return res;
}
};
后序遍历
后序遍历较为复杂,请看注释
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
// 定义一个pair结构,同时保存结点和该结点的状态(右子树是否已访问过)
stack<pair<TreeNode*, bool>> s;
vector<int> ret;
TreeNode* p = root;
while (!s.empty() || p){
if (p){
// 初始时状态设为true,标识右子树尚未访问,可以进行访问
s.push({p, true});
p = p->left;
}
else{
// 向上回溯时,不能立即弹出栈顶,而是先判断该结点是否还存在右子树
p = s.top().first->right;
bool status = s.top().second;
// 将栈顶结点右子树状态位设置位false,即已访问过,不允许再访问
s.top().second = false;
// 若右结点存在且尚未访问过,开始下一轮循环
if (p && status){
continue;
}
// 否则,证明该结点已无右节点,此时可以弹出该结点并输出
else{
ret.push_back(s.top().first->val);
s.pop();
// 置为null的目的是在上一步的判断处若status不满足条件时p不一定为null,需要手动置null
// 否则根据while循环的条件,可能会输出重复的值
p = nullptr;
}
}
}
return ret;
}
};