我们之前学习了二叉树的递归方法来实现二叉树的前中后序遍历,但是递归实现遍历,如果递归深度过深,就可能会导致程序崩溃,我们直到,栈空间很小,所以我们今天学习使用迭代的方式来实现:
题目链接:力扣前序遍历
先来回顾一下递归是怎么实现的,首先遍历二叉树的根,然后是左子树,右子树,但是左子树又被分为根,左子树,右子树,所以通过递归遍历时,先去保存结点的值,再向左子树递归,后向右子树递归。
我们通过迭代来实现二叉树的遍历,本质上还是模拟递归来实现,我们将分为以下两步:
- 先通过循环遍历左子树,直到为空,并且将遍历过的结点存在栈中。
- 从栈顶拿结点,再去访问栈顶结点的右子树。
Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
vector preorderTraversal(TreeNode* root) {
TreeNode* cur = root;
stack st;
vector v;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
v.push_back(cur->val);
cur = cur->left;
}
TreeNode* top = st.top();
st.pop();
cur = top->right;
}
return v;
}
};
题目链接:力扣中序遍历
中序遍历和前序遍历很像,只是保存到数组的时机不同,让我们思考一下,在前序遍历时,当一个结点出栈时,也就说明这个结点和这个结点的左子树一定以及访问过了,并且左子树中的结点也已经保存了,由于中序遍历, 是先访问左子树,然后是根,最后是右子树,所以在结点出栈之后,再去保存到vector中,就可以了。
Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
vector inorderTraversal(TreeNode* root) {
stack st;
vector v;
TreeNode* cur = root;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
st.pop();
v.push_back(top->val);
cur = top->right;
}
return v;
}
};
题目链接:力扣后序遍历
后序遍历与中序和前序有所不同,更加不容易掌握在什么时机去将节点中的数据保存到vector中,首先我们知道,后序遍历是先访问左子树,再访问右子树,最后访问根,所以要保存根结点时,必须满足要么右子树已经保存完了,要么就是右子树为空,其他和前序中序类似,只要控制栈是否为空和cur是否为空即可。
Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
vector postorderTraversal(TreeNode* root) {
stack st;
vector v;
TreeNode* cur = root;
TreeNode* prev = nullptr;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
//当数据出栈时,说明该数据和该数据的左子树已经访问
//而我们现在控制,第一个遍历到该数据时不出栈,只有该数据的
//右子树为空或者该数据的右子树就是上一个遍历的结点时
//才会进行出栈,出栈时将结点的val push到vector当中
if (!top->right || top->right == prev)
{
v.push_back(top->val);
prev = top;
cur = nullptr;
st.pop();
}
else
{
//通过该条语句让该节点的右子树去调用函数,就是
//一个重复调用的过程,只有当栈为空并且cur为空即
//全部遍历完
cur = top->right;
}
}
return v;
}
};
今天学习了使用非递归来实现二叉树的前中后序遍历,相比递归实现有一定难度,但是多多理解也不难。