前言
二叉树的遍历是一个经典问题,原本只是为了实现对二叉树的遍历,使用递归方法是最易读写和记忆的遍历方式,但是,但递归算法也有一个缺点:由递归调用自身所产生的函数调用栈找不方便,可能会使系统栈溢出,而且递归需要消耗过多的运行时间和系统栈空间,影响程序的效率。因此,如何使用迭代方法对二叉树进行遍历成了一种重要的算法。
一、定义二叉树结点
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {
}
};
先定义一个结点,里面包含了结点的值,和左右子树指针,以及初始化初始化构造函数。
二、迭代法实现前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> s;
if (root) s.push(root);
while (!s.empty())
{
TreeNode* node = s.top();
s.pop();
res.push_back(node->val);
if (node->right) s.push(node->right);
if (node->left) s.push(node->left);
}
return res;
}
};
在二叉树的遍历过程中,迭代法的基本思路是借助数据结构(如栈、队列等)来保存待访问的节点信息,以达到遍历的目的。
具体操作方法如下:
对于前序遍历,先将根节点入栈,然后重复以下操作:
1.弹出栈顶元素,并将其访问;
2.先将右子节点入栈;
3.再将左子节点入栈。
三、迭代法中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> s;
TreeNode* node = root;
while (node || !s.empty())
{
while (node)
{
s.push(node);
node = node->left;
}
node = s.top();
s.pop();
res.push_back(node->val);
node = node->right;
}
return res;
}
};
对于中序遍历,先将根节点入栈,然后重复以下操作:
1.若当前节点非空,则将其入栈,并将其左子节点设为当前节点;
2.若当前节点为空,则从栈中弹出一个元素,并访问该元素;
3.将当前节点设为弹出元素的右子节点。
四、迭代法后序遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> s;
TreeNode* pre = nullptr;
TreeNode* node = root;
while (node || !s.empty())
{
while (node)
{
s.push(node);
node = node->left;
}
node = s.top();
if (!node->right || node->right == pre)
{
res.push_back(node->val);
s.pop();
pre = node;
node = nullptr;
}
else
{
node = node->right;
}
}
return res;
}
};
对于后序遍历,先将根节点入栈,然后重复以下操作:
1.若当前节点非空,则将其入栈,并将其左子节点设为当前节点;
2.若当前节点为空,则取出栈顶元素进行判断,若不存在右子节点或者右子节点3.已经被访问过,则将其访问,否则将右子节点设为当前节点。