用系统堆栈实现(递归)
很容易实现:
- 前序:do(), 递归左儿子, 递归右儿子
- 中序:递归左儿子, do(), 递归右儿子
- 后序:递归左儿子, 递归右儿子, do()
用自定义栈实现(迭代法)
首先首先首先!!!
明确前中后序遍历的本质,即二叉树节点的访问顺序:
- 前序:中 -> 左 -> 右
- 中序:左 -> 中 -> 右
- 后序:左 -> 右 -> 中
中代表直接访问了一次该节点,左右代表访问一次其左右儿子
随想录链接:https://programmercarl.com/二叉树的迭代遍历.html#前序遍历-迭代法
前序的写法:
模拟递归法即可,唯一需要注意点就是,因为用的自己的栈,故如果想先左后右,那么必须先入栈右儿子
点击查看代码
while len(stack) != 0:
res.append(stack[-1].val)
node = stack.pop()
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
p = root
while p or stack:
if p:
stack.append(p)
p = p.left
else:
p = stack.pop()
res.append(p.val)
p = p.right
后序的写法:
这个是完全学习的随想录,实在没思路了。
先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图:
故调整下前序法的顺序(注意先右后左):
while len(stack) != 0:
res.append(stack[-1].val)
node = stack.pop()
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
最后来个res.reverse()
基于标记法的一种统一思路
中序
前文谈到迭代法的中序的写法不统一:问题出在左中右的中,前序后续的中都在最开始访问或最后,故能写得很统一简洁。
那么我们就能用标记法来解决,即:
- 检测节点是否是首次访问
- 是则将其弹出,放入右,中,左
- 在放中的时候再放入一个空指针
- 再弹栈的时候,若有空指针,则代表检测到该节点已是第二次访问了,马上弹出并入res结果
点击查看代码
def collectNode(self, node: TreeNode, res: List[int]):
if node is None:
return
stack = [node]
# 左中右
# 放入栈顺序为 右中左
while len(stack) != 0:
node = stack[-1]
if node:
stack.pop()
if node.right:
stack.append(node.right)
stack.append(node)
stack.append(None)
if node.left:
stack.append(node.left)
else:
stack.pop()
node = stack.pop()
res.append(node.val)