这里提供了三种方法:
从代码量和理解上来说,第三种方法是占优的。
def level_order(root) -> List[List[int]]: # 左程云所使用的方法,略繁琐,一般不用
if not root:
return []
queue, res = [root], []
line_res, last_one, nxt_last_one = [], root, None
while queue:
root = queue.pop()
line_res.append(root.v)
if root.left:
queue.insert(0, root.left)
nxt_last_one = root.left
if root.right:
queue.insert(0, root.right)
nxt_last_one = root.right
if root == last_one:
res.append(line_res)
line_res = []
last_one = nxt_last_one
return res
def level_order_2(root) -> List[List[int]]:
level_sign = "OVER" # 每层的结束标记符,也可以new一个Object()来替代
queue, res = [level_sign, root], [[]] # 注意初始化条件
while len(queue) > 1:
root = queue.pop()
if root == level_sign:
res.append([]) # 添加一个新子列表用于保存新层的节点
queue.insert(0, level_sign) # 插入该层的结束标记符号
elif root is not None:
res[-1].append(root.v) # 最新层的子列表添加、保存节点值
queue.insert(0, root.left)
queue.insert(0, root.right)
return res[:-1] # 丢弃最后一个插入的空列表(最后一层都是空节点)
def level_order_3(root) -> List[List[int]]:
queue, res = [root], []
while queue:
res.append([])
for _ in range(len(queue)): # 将当前队列在上一层中所有节点遍历完
root = queue.pop()
if root is not None:
res[-1].append(root.v)
queue.insert(0, root.left)
queue.insert(0, root.right)
return res[:-1]
锯齿遍历也可以基于层级遍历修改,即为奇数层res[-1].append(root.v)
,偶数层res[-1].insert(0, root.v)
。
先上一个模板法,同时可以非递归的得到二叉树的前序和中序遍历:
def pre_template(root):
st, res = [], []
while st or root:
if root: # 入栈,走向左子树
res.append(root.v) # 先序遍历输出
st.append(root)
root = root.left
else: # 出栈,走向它的右子树
root = st.pop()
res.append(root.v) # 中序遍历输出
root = root.right
return res
模板法的理解和栈回溯有关,建议自己画一棵树理解,能记很久。
模板法后序遍历二叉树需要进行一些小修改:
def pos_template(root):
st, res = [], []
state = {} # 访问状态表
while st or root:
if root: # 入栈,走向左子树
state[root] = "in" # 刚入栈
st.append(root)
root = root.left
else: # 出栈,走向它的右子树
if st[-1] in state: # 栈顶元素第一次被访问
state.pop(st[-1]) # 第一次回到这个点,出状态表,即标记为可出栈状态
root = st[-1].right # 走向右子树,但保留栈状态
else:
res.append(st.pop().v) # 出栈、后续输出
root = None # 置为空
return res
——主要的改动在于else: # 出栈,走向它的右子树
之后的代码,利用了一个状态访问表对访问次数进行计数,当且仅当某个节点被二次访问后才退栈并被输出。请参考这篇文章中的图例进行理解。
特别的,前序遍历还可以使用另外一种更简短的方法:
def pre_short(root):
st, res = [root], []
while st:
node = st.pop()
if not node:
continue
res.append(node.v) # 先序输出
st.append(node.right) # 先压右后压左
st.append(node.left)
return res
由于该方法利用了根节点和函数栈性质,因此无法适用于中序遍历,但可以修改成后序遍历的版本:
def pos_short(root):
st, res = [root], []
while st:
node = st.pop()
if not node:
continue
st.append(node.left) # 此时先压左后压右
res.insert(0, node.v) # 后序输出,注意此时向队列首部添加新元素
st.append(node.right)
return res