二叉树迭代方式遍历(前/中/后/层)
前言
刷leetcode的时候做到一个二叉树前序遍历的题,上来就完全不思考就想着去用递归做,确实比较方便,但是题目要求里面写了尝试用迭代方法,想了一会发现自己把自己绕晕了,所以在这里记录一下。
二叉树遍历的概念:
说到二叉树的遍历,我们一般遇到的就四种形式:前序遍历,中序遍历,后序遍历以及层序遍历。其中前中后这三个的意思其实分别代表的是头节点在遍历的时候所在位置(在左右结点之前/中/后) 用图形表示就是:
那么我们可以得到:
前序遍历:1->2->3
中序遍历:2->1->3
后序遍历:2->3->1
而层序遍历其实看名字就能看出来就不介绍了。
迭代法进行二叉树遍历
那么为什么我们可以用迭代法进行二叉树遍历呢,实际上我们要借用的是栈与队列的性质,我们知道使用递归其实就是为了保存父节点的参数,那么我们把父节点存在栈或者队列里面然后再取出来也可以达到同样的效果,原理就是这么个原理,下面来介绍具体操作。
前序遍历
由于前序遍历的顺序是中->左->右,所以我们在放一个点进去之前,需要先把这个点的本身的值先取出来,然后取左边的点,如果左节点还有左节点,那么该节点的右节点需要等左边的一串都取完了之后,才轮到右节点被存储,这样我们可以看作是把右节点压在栈底然后放出来,我们画这样的图:
这样我们根据弹出的顺序就可以得到1->2->4->3这一前向遍历的结果,这种思想转化为代码如下:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> temp;
vector<int> ans;
if (root == NULL) return ans;
temp.push(root);
while (!temp.empty()) {
TreeNode* node = temp.top();
temp.pop();
ans.push_back(node->val);
if (node->right!=nullptr) temp.push(node->right);
if (node->left!=nullptr) temp.push(node->left); // 顺序要注意,先进去的在下面,所以先右后左
}
return ans;
}
};
中序遍历
看完了前序遍历,我们再来看中序遍历,我们知道中序遍历的顺序是左->中->右,所以最开始的点应该是从左走到头的节点,然后一点一点往上走回去,因此我们这里还是使用栈的模式,我们来模拟一下:
这样我们的到中序遍历的结果:4->2->1->3,同上我们把程序代码写出来:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans;
stack<TreeNode*> temp;
TreeNode* note = root;
while (note != nullptr || !temp.empty()) {
if (note != nullptr) { // 到底了
temp.push(note); // 直接把中放进栈
note = note->left; //继续往左
}
else {
note = temp.top();
temp.pop();
ans.push_back(note->val);
note = note->right; // 先把中弹出来再放右进去
}
}
return ans;
}
};
后序遍历
后序遍历我们可以偷个懒,因为后序遍历的顺序是左->右->中,所以我们可以通过对前序遍历的代码进行更改很方便的得到后序遍历的结果,方法如下:
首先将先序遍历的左右节点的代码交换,先序遍历就变成了中->右->左,然后再将结果的顺序反转,就得到了左->右->中(后序遍历)
代码如下:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> temp;
vector<int> ans;
if (root == NULL) return ans;
temp.push(root);
while (!temp.empty()) {
TreeNode* node = temp.top();
temp.pop();
ans.push_back(node->val);
if (node->left!=nullptr) temp.push(node->left);
if (node->right!=nullptr) temp.push(node->right); // 这两步顺序换过来了
}
reverse(ans.begin(),ans.end());//结果反转
return ans;
}
};
层序遍历
其实层序遍历应该是这里面最简单的遍历方式了,我们在这里改用队列的形式进行,先进去的先出来,我们还是老规矩,先画图画队列变化:
废话就不说了,直接上代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
queue<TreeNode*> temp;
vector<int> ans;
if (root == NULL) return ans;
temp.push(root);
while (!temp.empty()) {
TreeNode* node = temp.front();
temp.pop();
ans.push_back(node->val);
if (node->left!=nullptr) temp.push(node->left);
if (node->right!=nullptr) temp.push(node->right);
}
return ans;
}
};
最简单的代码了…
(这个主要是参照代码随想录的文章写的,不过改的给自己看的容易懂一点…)