上期讲到二叉树的递归遍历, 那么本期来讲一下非递归遍历, 也就是迭代版本的代码怎么写
1、 前序遍历
中左右
用栈来模拟递归的过程, 特点是先进后出
入栈的元素首先放入栈底, 然后每次从栈顶弹出, 这也就是为什么先进后出
遇到root, 把10入栈
然后处理根节点, 弹出10, 同时push到 Res里
然后把左右孩子入栈, 这里为5和20, 注意因为最后是中左右的顺序, 而且栈是先进后出, 所以这里是先要把右孩子入栈, 再把左孩子入栈, 这样才能先弹出左孩子, 再弹出右孩子
弹出5, 同时把5 加入到Res里
然后继续处理 5 的左右孩子, 因为是中左右, 要先处理完左子树, 才能处理右子树, 所以此时是处理 5 的左右孩子, 为 4 和 6 ,即先把右孩子 6 入栈, 再把左孩子 4 入栈, 这样弹出的时候才能先弹出左孩子, 再弹出右孩子
弹出 4 , 把 4 加入到Res里
此时 4 已经是叶子节点了, 即没有左右孩子, 所以继续弹出 6 , 同时 把 6 加入到 Res
6 也是 叶子节点, 没有左右孩子, 则继续弹出 20 , 把 20 加入到 Res 里
然后把 20 的左右孩子入栈, 按照先进后出的原则, 先入右孩子, 再入左孩子
然后 弹出 2, 把 2 加入到 Res里
2 是叶子节点, 没有左右孩子, 继续弹出, 把 8 加入到 Res里
至此, 整个二叉树遍历完毕, 输出 10, 5, 4, 6, 20, 2, 8
代码实现
# 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) # 首先把根节点加进来
while stack: # 只要栈不为空, 就一直执行
temp = stack.pop() # 入栈后, 我们要先弹出, 然后把val 加入到Res, 同时把左右孩子入栈
res.append(temp.val)
if temp.right: # 因为栈是先进后出, 所以先加右孩子, 当然 先要判断右孩子是否存在
stack.append(temp.right)
if temp.left # 再加 左孩子, 这样在下次pop的时候才能保证先弹出的是左孩子
stack.append(temp.left)
return res
2、 后序遍历
左右中
如果把左右中 颠倒一下 就是中右左, 然后把右左 换一下顺序呢 是不是就是中左右
看到中左右能想到什么, 不就是前序遍历吗?
那其实 现在我们只需要把上面代码改成中右左, 然后把结果 reverse一下, 就是我们的后序遍历
代码实现
先加入左孩子, 再加入右孩子, 弹出元素的时候就会先弹右孩子, 再弹出左孩子, 这样最后得到的结果就是中右左, 然后颠倒一下 左右中, 即是我们的后续遍历
# 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]:
if not root: return []
stack, res = [root], []
while stack:
temp = stack.pop()
res.append(temp.val)
if temp.left: # 先加入左孩子
stack.append(temp.left)
if temp.right: # 再加入右孩子
stack.append(temp.right)
return res[::-1] // reverse一下
3、中序遍历
左中后
这个会比较特殊一点, 因为是先遍历左孩子, 然后处理根节点, 再遍历右孩子
前序和后序都是遍历根节点的同时 就处理了根节点, 而中序是要先遍历左孩子, 才能处理根节点.
下期会着重讲中序遍历(帕鲁先生累了, 呜呜呜)