在刷 leetcode 二叉树相关的题目时,经常有这样给定的例子,例如: 检查平衡性
实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/check-balance-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
如果我们想要在本地调试程序,就需要生成相应的二叉树,进而调试代码。然而,每次如果要手动添加 Node 来生成树是非常麻烦的。
根据示例,给我们的是一个分层顺序列表 类似于 [3,9,20,null,null,15,7]
。我们可以非常直观的知道 3 是根结点, 9 和 20 是 3 的左右子节点, null 和 null 是 9 的左右子节点,15 和 7 是 20 的左右子节点。
从上面的描述中,可以发现分配左右节点的先后顺序也是 3,9,20,跟列表顺序是一致的,即先给 3 分配左右节点,再给 9 分配左右节点,再给 20 分配左右节点,如果列表更长,接下来会跳过null,给 15 分配左右节点,再给 7 分配左右节点。
因此,我们可以用队列来实现二叉树的初始化中这种先入先出的特点。下面的图示说明了队列初始化二叉树的过程:
# 节点类
class Node(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
# 树生成代码
def generate_tree(vals):
if len(vals) == 0:
return None
que = [] # 定义队列
fill_left = True # 由于无法通过是否为 None 来判断该节点的左儿子是否可以填充,用一个记号判断是否需要填充左节点
for val in vals:
node = Node(val) if val is not None else None # 非空值返回节点类,否则返回 None
if len(que)==0:
root = node # 队列为空的话,用 root 记录根结点,用来返回
que.append(node)
elif fill_left:
que[0].left = node
fill_left = False # 填充过左儿子后,改变记号状态
if node: # 非 None 值才进入队列
que.append(node)
else:
que[0].right = node
if node:
que.append(node)
que.pop(0) # 填充完右儿子,弹出节点
fill_left = True #
return root
# 定义一个dfs打印中序遍历
def dfs(node):
if node is not None:
dfs(node.left)
print(node.val, end=' ')
dfs(node.right)
# 定义一个bfs打印层序遍历
def bfs(node):
que = []
que.append(node)
while que:
l = len(que)
for _ in range(l):
tmp = que.pop(0)
print(tmp.val, end=' ')
if tmp.left:
que.append(tmp.left)
if tmp.right:
que.append(tmp.right)
print('|', end=' ')
# test
null = None
vals = [3,9,20,null,null,15,7]
tree = generate_tree(vals)
print('中序遍历:')
dfs(tree) # 9 3 15 20 7
print('\n层序遍历:')
bfs(tree) # 3 | 9 20 | 15 7 |