文章目录
上一篇文章介绍了二叉树的几种遍历方式的递归写法,这篇文章继续介绍他们的迭代写法。没有看过的小伙伴可以戳这个链接
前序遍历
题目链接
前序遍历意思就是按照“根节点-左子树-右子树”的顺序来遍历二叉树,通过递归方法来实现的话很简单,但要用迭代的话就略显麻烦一点了。我们需要借助一个栈来进行辅助实现迭代的遍历,在遍历时,需要先将右节点放到队列里,再放左节点,因为这样才能让出栈顺序是“根左右”,具体的,对python来说,我们可以用列表来作为栈。
代码\Python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = []
res = []
stack.append(root)
print(stack)
while len(stack):
node = stack.pop()
# 根节点
res.append(node.val)
# 右节点入栈
if node.right:
stack.append(node.right)
# 左节点入栈
if node.left:
stack.append(node.left)
return res
代码\C++
/**
* 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<int> preorderTraversal(TreeNode* root) {
if(!root){
return {};
}
vector<int> res;
stack<TreeNode*> st;
TreeNode *node = nullptr;
st.push(root);
while(!st.empty()){
node = st.top();
st.pop();
res.push_back(node->val);
if(node->right){
st.push(node->right);
}
if(node->left){
st.push(node->left);
}
}
return res;
}
};
中序遍历
题目链接
类似的,中序遍历就是遍历的时候把根节点放到中间,即“左子树-根节点-右子树”的顺序。但遍历写法不能轻松修改上面的前序,不能简单的把代码改一下顺序就行。
具体的,我们需要借助一个指针来帮助遍历,我们需要一直先访问左节点,将碰到的节点先放到栈中,直到没有左节点之后再往回走访问中间节点和右节点。
代码\Python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = []
res = []
cur = root
while cur or stack:
# 中间节点不为空
if cur:
stack.append(cur)
cur = cur.left
# 没有左节点了,可以往回了
else:
# 上一层的中间节点
cur = stack.pop()
res.append(cur.val)
cur = cur.right # 右节点
return res
代码\C++
if(!root) {
return {};
}
vector<int> res;
stack<TreeNode*> sk;
TreeNode *cur = root;
while(cur || !sk.empty()){
if(cur){
sk.push(cur);
cur = cur->left;
}
else{
cur = sk.top();
sk.pop();
res.push_back(cur->val);
cur = cur->right;
}
}
return res;
后序遍历
添加链接描述
类似的,后序遍历就是遍历的时候把根节点放到最后,即“左子树-右子树-根节点”的顺序。后序遍历的非递归写法有些麻烦,不过让我们慢慢来,后序的顺序是 左右中,而前序的顺序是中左右,因此我们可以直接在前序遍历的代码上改一下顺序:先让前序遍历变成中右左,再将其逆序,就是左右中。这里python代码就省略了。
代码\C++
/**
* 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<int> postorderTraversal(TreeNode* root) {
if(!root){
return {};
}
vector<int> res;
stack<TreeNode*> st;
TreeNode *node = nullptr;
st.push(root);
while(!st.empty()){
node = st.top();
st.pop();
res.push_back(node->val);
// 交换前序遍历中的左右顺序
if(node->left){
st.push(node->left);
}
if(node->right){
st.push(node->right);
}
}
// 再反转结果
reverse(res.begin(), res.end());
return res;
}
};
后序遍历-进阶写法
上一个简单的思路有些取巧,复杂一点的写法需要在遍历过程中记录某个结点是否访问过,具体的,我们可以用一个集合存储访问过的节点。
代码\Python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
cur = root
stack = []
# 标记遍历过的左右子树
visited = set()
res = []
while cur or stack:
if cur:
# 当前中节点入栈,
stack.append(cur)
# discard方法及时参数不在里面,也不会报错,remove方法会报错
visited.discard(cur)
# 遍历左子树
cur = cur.left
else:
# 取栈顶
cur = stack[-1]
if cur not in visited:
# 左子树已遍历,右子树还没
visited.add(cur)
cur = cur.right
else:
# 左右都已遍历完,访问根节点
res.append(cur.val)
# 出栈
stack.pop()
# cur 置空,回循环取栈顶继续判断
cur = None
return res
代码\C++
/**
* 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<int> postorderTraversal(TreeNode* root) {
if(!root){
return {};
}
vector<int> res;
stack<TreeNode*> st;
set<TreeNode*> visited;
TreeNode *cur = root;
while(cur || !st.empty()){
if(cur){
st.push(cur);
// 如果访问过
if(auto it = visited.find(cur);
it != visited.end()){
// 就将它置0
visited.erase(it);
}
cur = cur->left;
}
else{
// 取栈顶
cur = st.top();
if(visited.count(cur)){
res.push_back(cur->val);
st.pop();
cur = nullptr;
}
else{
// 左子树遍历完
visited.insert(cur);
cur = cur->right;
}
}
}
return res;
}
};
层序遍历
题目链接
层序遍历一般指对二叉树进行从上到下从左到右的一层一层的遍历,同样深度的节点在同一层。迭代的层序遍历需要借助一个队列,类似于广度优先搜索一样。
代码\Python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
from queue import Queue
que = Queue()
que.put(root)
res = []
while not que.empty():
tmp = []
length = que.qsize()
for _ in range(length):
node = que.get()
tmp.append(node.val)
if node.left:
que.put(node.left)
if node.right:
que.put(node.right)
res.append(tmp)
return res
代码\C++
/**
* 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<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root){
return res;
}
queue<TreeNode *> que;
que.push(root);
int size = 0, i;
TreeNode *node = nullptr;
while(!que.empty()){
size = que.size();
vector<int> tmp;
for(i = 0; i < size; i++){
node = que.front();
que.pop();
tmp.push_back(node->val);
if(node->left){
que.push(node->left);
}
if(node->right){
que.push(node->right);
}
}
res.push_back(tmp);
}
return res;
}
};
总结
最常见最基础的4种二叉树的迭代遍历方式,也是二叉树很多题目的基础算法,如果对你有帮助的话,动动手指点个赞吧!