相信只要了解过二叉树,都知道二叉树的3种遍历方式:前序遍历、中序遍历、后序遍历。
甚至不夸张的说,其递归的遍历方法闭着眼睛也能写出来。所以本篇意不在记录其递归的写法,而是探寻其迭代的方法。
0、定义二叉树
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
1. 前序遍历
想要理解或者实现前序遍历方法,我们可以从其递归方法入手,了解其实现过程。
class Solution:
def preorderTraversal(self, root: TreeNode):
res = []
def dfs(root):
nonlocal res
if not root:
return
res.append(root.val)
dfs(root.left)
dfs(root.right)
dfs(root)
return res
将其递归的过程展开,就如同其下的方式:访问当前节点,进入左子节点,然后访问当前节点的左子节点……,遇到null则返回,然后访问节点的右子节点,由于节点不能反向找到其父节点,我们需要保存其右子节点。同时,我们需要从最近的右子节点开始访问,也即利用栈来代替递归算法中的调用栈。
dfs(root)
print(root.val)
dfs(root.left)
print(root.left.val)
dfs(root.left)
null return
dfs(root.right)
print(root.right.val)
dfs(root.left)
...
下面是其迭代方法的实现
class Solution:
def preorderTraversal(self, root):
res = []
stack = []
while stack or root:
while root:
res.append(root.val)
stack.append(root.right)
root = root.left
root = stack.pop()
return res
2. 中序遍历
中序遍历的递归调用过程如下,深入左子节点,当其为空则返回,访问节点,然后进入其右子节点。重复该过程。
dfs(root)
dfs(root.left)
dfs(root.left)
null return
print(root.val)
dfs(root.right)
dfs(root.left)
dfs(root.left)
...
可以看到,我们需要先将左子节点保存,待其为空后,当问节点,进入右子树,继续……
class Solution:
def inorderTraversal(self, root: TreeNode):
res = []
stack = []
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
res.append(root.val)
root = root.right
return res
3. 后序遍历
后序遍历可以看着是前序遍历的镜像,所以可以套用前序遍历的方法,但是需要将最后结果进行反转。
class Solution:
def postorderTraversal(self, root):
res = []
stack = []
while stack or root:
while root:
res.append(root.val)
stack.append(root.left)
root = root.right
root = stack.pop()
return res[::-1]
4. 颜色标记法
这个方法是leetcode解题中,针对前中后序遍历均适用,而且容易理解。
以后序遍历为例,其代码如下。需要注意的是,因为栈的后进先出结构,所以我们的入栈顺序为相反方向。
同理,如果是前序遍历,则入栈顺序为:右、左、中;
中序遍历的入栈顺序为:右、中、左。
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
res = []
white, gray = 1, 0
stack = [(white, root)]
while stack:
color, node = stack.pop()
if not node:
continue
if color == white:
stack.append((gray, node))
stack.append((white, node.right))
stack.append((white, node.left))
else:
res.append(node.val)
return res
5. leetcode
94. 二叉树的中序遍历
145. 二叉树的后序遍历
6. 参考
1、https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/
2、https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/die-dai-fa-by-jason-2/