二叉树在数据结构中具有十分重要的作用,很多算法题都使用到树的思想。将复杂的算法题转化为简单子问题,并用树的形式表示,可以直观理解划分的过程,有利于分析和写出算法程序。比如:对于递归问题,就可以转化成树的形式,将树的叶节点作为终止条件,将树的生成过程作为迭代公式,根据题目要求使用先序、中序、后序遍历,下面总结有关二叉树的相关题目,二叉树的题目普遍可以用递归
和迭代
的方式来解:
首先写出二叉树的结构:
class TreeNode:
def __init(self, x):
self.val = x
self.left = None
self.right = None
1、求二叉树的最大深度
def max_depth(self, node):
"""
求二叉树的最大深度
"""
if node is None:
return 0
left = self.max_depth(node.left)
right = self.max_depth(node.right)
return max(left, right) + 1
2、求二叉树的最小深度
def min_depth(self, node):
"""
求二叉树的最小深度
"""
if node is None:
return 0
left = self.min_depth(node.left)
right = self.min_depth(node.right)
return min(left, right) + 1
3、求二叉树中节点的个数
def node_count(self, node):
"""
求二叉树中节点的个数
"""
if node is None:
return 0
left = self.node_count(node.left)
right = self.node_count(node.right)
return left + right + 1
4、求二叉树中叶子节点的个数
def leaf_node_count(self, node):
"""
求二叉树中叶子节点的个数
"""
if node is None:
return 0
if node.left is None and node.right is None:
return 1
left = self.leaf_node_count(node.left)
right = self.leaf_node_count(node.right)
return left + right
5、求二叉树中第k层节点的个数
def k_level_count(self, node, k):
"""
求二叉树中第k层节点的个数
"""
if k < 1 or node is None:
return 0
if k == 1:
return 1
left = self.k_level_count(node.left, k-1)
right = self.k_level_count(node.right, k-1)
return left + right
6、后序遍历的应用:判断二叉树是否是平衡二叉树
"""
使用后序遍历,每个节点只遍历一次,效率高
"""
def is_balance_binary_tree(self, node):
"""
判断二叉树是否是平衡二叉树
"""
return self.max_depth2(node) != -1
def max_depth2(self, node):
"""
检查树是否平衡
"""
if node is None:
return 0
left = self.max_depth2(node.left)
right = self.max_depth2(node.right)
if left == -1 or right == -1 or math.fabs(left - right) > 1:
return -1
return max(left, right) + 1
7、层次遍历的应用:判断二叉树是否是完全二叉树
@staticmethod
def is_complete_binary_tree(node):
"""
判断二叉树是否是完全二叉树:层次遍历,如果一个节点缺少孩子,则剩下的节点都应该没有孩子。
"""
if node is None:
return True
_queue = queue.Queue()
_queue.put(node)
has_no_child = False
result = True
while not _queue.empty():
current_node = _queue.get()
if not has_no_child:
if current_node.left is not None and current_node.right is not None:
_queue.put(current_node.left)
_queue.put(current_node.right)
elif current_node.left is None and current_node.right is not None:
result = False
break
elif current_node.left is not None and current_node.right is None:
_queue.put(current_node.left)
has_no_child = True
else:
has_no_child = True
else:
if current_node.left is not None or current_node.right is not None:
result = False
break
return result
8、两个二叉树是否完全相同
def is_common_tree(self, node1, node2):
"""
两个二叉树是否完全相同
"""
if node1 is None and node2 is None:
return True
elif node1 is None or node2 is None:
return False
if node1.val != node2.val:
return False
left = self.is_common_tree(node1.left, node2.left)
right = self.is_common_tree(node1.right, node2.right)
return left and right
9、两个二叉树是否互为镜像
def is_mirror(self, node1, node2):
"""
两个二叉树是否互为镜像
"""
if node1 is None and node2 is None:
return True
elif node1 is None or node2 is None:
return False
if node1.val != node2.val:
return False
left = self.is_mirror(node1.left, node2.right)
right = self.is_mirror(node1.right, node2.left)
return left and right
10、翻转二叉树 or 镜像二叉树
def mirror_tree_node(self, node):
"""
翻转二叉树 or 镜像二叉树
"""
if node is None:
return None
left = self.mirror_tree_node(node.left)
right = self.mirror_tree_node(node.right)
# 每次都新建节点,不然会修改原始链表
new_node = TreeNode(node.val)
new_node.left = right
new_node.right = left
return new_node
11、二叉树的先序遍历(应用见No.15)
def pre_order(self, node):
"""
二叉树的先序遍历
"""
# result存放先序遍历结果
result = []
self.pre(node, result)
return result
def pre(self, node, result):
if node is None:
return
result.append(node.val)
self.pre(node.left, result)
self.pre(node.right, result)
12、二叉树的中序遍历(应用见No.16)
def in_order(self, node):
"""
二叉树的中序遍历
"""
result = []
self.inside(node, result)
return result
def inside(self, node, result):
if node is None:
return
self.inside(node.left, result)
result.append(node.val)
self.inside(node.right, result)
13、二叉树的后序遍历(应用见No.6)
def post_order(self, node):
"""
二叉树的后序遍历
"""
result = []
self.post(node, result)
return result
def post(self, node, result):
if node is None:
return
self.post(node.left, result)
self.post(node.right, result)
result.append(node.val)
14、二叉树的层次遍历(应用见No.7)
@staticmethod
def level_order(node):
"""
二叉树的层次遍历
"""
if node is None:
return
result = []
_queue = queue.Queue()
_queue.put(node)
while not _queue.empty():
current_node = _queue.get()
result.append(current_node.val)
if current_node.left is not None:
_queue.put(current_node.left)
if current_node.right is not None:
_queue.put(current_node.right)
return result
15、二叉树先序遍历的应用:输入一个二叉树和一个整数,打印出二叉树中节点值的和等于输入整数所有的路径(本例展示了如何输出满足条件的路径)
class Solution:
def __init__(self):
self.result = []
def find_path(self, node, sum):
"""输入一个二叉树和一个整数,打印出二叉树中节点值的和等于输入整数所有的路径"""
if node is None:
return
stack = []
path_sum = 0
self.find_sum_core(node, sum, stack, path_sum)
def find_sum_core(self, node, sum, stack, path_sum):
stack.append(node.val)
path_sum += node.val
if node.left is None and node.right is None:
if path_sum == sum:
self.result.append(copy.deepcopy(stack))
if node.left is not None:
self.find_sum_core(node.left, sum, stack, path_sum)
if node.right is not None:
self.find_sum_core(node.right, sum, stack, path_sum)
stack.pop(-1)
缓存数组stack中添加路径节点,在满足终止条件返回父节点时,需要将当前节点从缓存中弹出,恢复现场(类似于递归,这里需要手动恢复)。
应用:
一只青蛙一次可以跳3级、4级或5级台阶,每一级台阶使用不同数量的石子组成,例如:数组[0, 3, 1, 3, 4, 1, 5, 6, 7]表示第一级台阶由3个石子组成,第二级台阶由1个石子组成,求青蛙从0的位置跳到最后一级台阶经过的最少石子的
import copy
class Solution:
def __init__(self):
self.path = []
self.path_sum = []
def get_minimum_stones(self, road_stone_list):
length = len(road_stone_list)
path = []
path_sum = 0
return self.get_minimum_stones_core(road_stone_list, path, path_sum, length-1)
def get_minimum_stones_core(self, data, path, path_sum, n):
path.append(data[n])
path_sum += data[n]
if 3 <= n <= 5:
self.path.append(copy.deepcopy(path))
self.path_sum.append(path_sum)
if n > 3:
self.get_minimum_stones_core(data, path, path_sum, n - 3)
if n > 4:
self.get_minimum_stones_core(data, path, path_sum, n - 4)
if n > 5:
self.get_minimum_stones_core(data, path, path_sum, n - 5)
path.pop(-1)
if __name__ == '__main__':
data = [0, 3, 1, 3, 4, 1, 5, 6, 7]
S = Solution()
S.get_minimum_stones(data)
print("所有可行的路径:", S.path)
print("路径的长度:", S.path_sum)
# 取其中一个最小值
print("最短路径:", S.path[S.path_sum.index(min(S.path_sum))])
输出结果:
所有可行的路径: [[7, 1], [7, 4], [7, 3]]
路径的长度: [8, 11, 10]
最短路径: [7, 1]
16、中序遍历的应用:二叉搜索树的第k个结点
"""
题目:给定一棵二叉搜索树,请找出其中的第k大的结点。
思路:
本题参考二叉搜索树的中序遍历,先找右子树,再找左子树,最终可以得到从大到小的输出。
"""
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def find_kth_node(self, root, k):
if root is None or k <= 0:
return
kth = [0]
self.find_kth_node_core(root, k, kth)
def find_kth_node_core(self, node, k, kth):
if node is None or k < 0:
return
self.find_kth_node_core(node.right, k, kth)
kth[0] += 1
if kth[0] == k:
print("二叉搜索树中第 %s 大的数:%s" % (k, node.val))
self.find_kth_node_core(node.left, k, kth)
if __name__ == '__main__':
node1 = TreeNode(5)
node2 = TreeNode(3)
node3 = TreeNode(7)
node4 = TreeNode(2)
node5 = TreeNode(4)
node6 = TreeNode(6)
node7 = TreeNode(8)
node1.left = node2
node1.right = node3
node2.left = node4
node2.right = node5
node3.left = node6
node3.right = node7
S = Solution()
S.find_kth_node(node1, 6)
输出:
二叉搜索树中第 6 大的数:3
关于二叉树相关题目的完整程序见:github