讲完了二叉树前序遍历和后序遍历的非递归代码, 那么这期我们来讲一下中序遍历的非递归实现
1、中序遍历
左中右
对于一棵树而言, 我们都是先遍历根节点, 然后依次遍历左右孩子
对于前序和后序遍历而言, 我们都是先处理根节点, 我们发现 处理和遍历是在一起的
但是对于中序遍历来说, 我们需要先遍历根节点 10, 然后遍历左子树 5-> 4 -> 6, 然后 4 才是我们的处理节点, 然后再处理 5 , 再处理 6 , 最后再返回处理 根节点 10
模拟入栈过程
因为最后结果是左中右, 所以我们要把最左边的节点弹出 存入Res里, 这里会从根节点开始, 一直遍历左孩子, 直到遇到叶子节点, 即把 10 , 5 , 4 先后入栈
遵循以下原则:
遇到一个节点, 只要左不为空, 就一直遍历他的左孩子, 同时入栈, 为空, 则从栈顶弹出元素, 假设是A, 再遍历A的右孩子, 空则继续弹出元素, 非空则再遍历右孩子的左节点......
此时我们发现节点 4 的左孩子为空, 则弹出 4 , 同时加入Res
发现 4 的右孩子为空, 则继续弹出元素, 把 5 加入 Res
发现 5 的 右孩子 6 不为空, 则 把 6 入栈
发现 6 的左孩子为空, 则弹出 6, 同时加入Res
6 的 右孩子为空, 继续弹出元素, 把 10 加入Res
发现 10 的右孩子不为空, 则把右孩子 20 入栈
遇到一个节点, 优先检查他的左孩子是否有值, 发现不为空, 则把 2 入栈
2 的左孩子为空, 则弹出元素, 同时加入到Res
2 的右孩子为空, 则继续弹出, 把 20 加入到Res
发现 20 的右孩子非空, 把 8 入栈
8 的左孩子为空, 弹出元素, 加入 Res
8 的右孩子也为空, 但此时栈已空, 无法弹出元素, 遍历结束
得到 4, 5, 6, 10, 2, 20, 8
遇到一个节点, 优先找他的左孩子
- 非空, 入栈, 继续找他的左孩子
- 空, 从栈顶弹出元素
弹出元素后, 找他的右孩子
- 非空, 遇到一个节点, 此时应该干嘛?(重复一开始的步骤, 找他的左孩子)
- 空, 弹出元素
栈为空, 结束遍历
2、代码实现
叶子节点本身也是棵树, 只不过左为空, 右为空, 所以对于叶子节点来说, 也遵循上述原则, 先找左, 叶子节点的左孩子为空, 所以栈顶弹出元素(叶子节点), 然后找叶子节点的右孩子, 也为空, 则继续弹出(其实此时弹出的已经是叶子节点的父节点了), 找叶子节点的父节点的右孩子, 以此反复...
# 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]:
res, stack = [], []
# 从根节点开始查找
while stack or root:
if root: # 遇到一个节点就先找left
stack.append(root)
root = root.left # 优先找left, 只要left有值, 就会入栈
else:
temp = stack.pop() # left 为空, 则弹出
res.append(temp.val) # 记录
root = temp.right # 找右孩子
return res
至此, 二叉树前中后序的递归版本和迭代版本已经讲解完毕, 接下来会讲层次遍历