二叉树遍历框架(递归与非递归)
1.递归写法
递归写法很简单,只需按根出现的顺序改变将根节点加入返回结果的顺序(递归调用前/中/后)即可。
1.1.前序
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
def helper(root):
if not root:
return
ret.append(root.val)
helper(root.left)
helper(root.right)
helper(root)
return ret
1.2.中序
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
def helper(root):
if not root:
return
helper(root.left)
ret.append(root.val)
helper(root.right)
helper(root)
return ret
1.3.后序
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
def helper(root):
if not root:
return
helper(root.left)
helper(root.right)
ret.append(root.val)
helper(root)
return ret
2.非递归写法
非递归写法中,需要额外用一个list模拟栈(stack)来记录节点的访问状态,同时用一个list(ret)记录遍历结果。下面用一种统一且方便记忆的框架来实现二叉树的非递归遍历。
1.1.前序
前序遍历即根左右的方式遍历二叉树。最后得到的遍历结果为:(根1)(左1)(右1) --> (根1)(根2左2右2)(根3左3右3) --> ...,即:
- 若根节点非空,将其左子节点同时加入res和stack中,更新根节点为其左子节点;
- 若根节点为空,弹出stack栈顶元素,如果该元素有右子节点,将根节点更新为其右子节点。重复1,直到stack为空。代码如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
stack=[]
# 栈非空,排除初始条件
while root or stack:
# 更新root同时加入ret和stack
while root:
ret.append(root.val)
stack.append(root)
root=root.left
# 遍历右子节点
if stack:
node=stack.pop()
if node.right:
# 从右子节点开始循环
root=node.right
return ret
1.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 postorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
stack=[]
while root or stack:
while root:
ret.append(root.val)
stack.append(root)
# 先处理右子树
root=root.right
if stack:
node=stack.pop()
# 再处理左子树
if node.left:
root=node.left
# 逆序
return ret[::-1]
1.3.中序
中序遍历的顺序是左根右,和前序遍历类似,但不同的一点是,只有当从stack弹出元素时,我们才遍历这个节点。
一个很直观的理解是:中序遍历的第一个元素是最左边节点的值,所以是用左子节点更新根节点时压入stack的最后一个元素,即第一次不满足条件时弹出的那个元素。代码如下:
# 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: TreeNode) -> List[int]:
ret=[]
stack=[]
while root or stack:
while root:
stack.append(root)
root=root.left
if stack:
node=stack.pop()
# 从栈弹出时遍历
ret.append(node.val)
if node.right:
root=node.right
return ret