🏫博客主页:魔王-T
🏯系列专栏:结构算法
🥝大鹏一日同风起 扶摇直上九万里
❤️感谢大家点赞👍收藏⭐评论✍️
本文将介绍二叉树的基本概念、性质,并通过程序解析二叉树的构建、遍历和其他操作,最后总结二叉树的重要性和应用。二叉树是计算机科学中常用的一种数据结构,它在许多算法和应用中发挥着重要作用。本文将介绍二叉树的基本概念、性质,并通过程序解析二叉树的构建、遍历和搜索等操作,最后总结二叉树的重要性和应用。
🏳️🌈基本概念和性质
二叉树(Binary Tree)是一种树形数据结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树可以是有序的或无序的,有序二叉树要求左子节点的值小于父节点,右子节点的值大于父节点。二叉树的一些重要性质包括:
- 🍔叶子节点数:没有子节点的节点数。
- 🍔二叉树的深度:二叉树的深度指的是从根节点到最远叶子节点的最长路径上的节点个数。可以使用递归或迭代的方式来计算二叉树的深度。
使用递归方式计算二叉树的深度:
①如果二叉树为空树,则深度为0。
②如果二叉树不为空,则深度等于左子树和右子树的深度中较大的值加1。
下面是一个二叉树的结构实例示例:
假设我们有以下二叉树:
我们可以使用一个队列来进行层次遍历,并同时记录每一层的节点数量:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def tree_depth(root):
if root is None:
return 0
queue = [root] # 初始化队列,将根节点加入队列
depth = 0 # 初始化深度为0
while queue:
level_size = len(queue) # 当前层的节点数量
depth += 1 # 深度加1
for _ in range(level_size):
current_node = queue.pop(0) # 出队列
if current_node.left:
queue.append(current_node.left) # 将左子节点加入队列
if current_node.right:
queue.append(current_node.right) # 将右子节点加入队列
return depth
# 构建二叉树
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.right = TreeNode(6)
print(tree_depth(root)) # 输出: 3
在这个示例中,二叉树的深度为3。
- 🍔完全二叉树(Complete Binary Tree):对于一颗二叉树来说,如果除了最后一层外,其他层的节点数都达到最大值,并且最后一层的节点都集中在左侧连续位置,那么这颗二叉树就是完全二叉树。换句话说,在完全二叉树中,除了最后一层外,其他层都是满的,最后一层可以不满,但节点都集中在左侧。
- 🍔满二叉树(Full Binary Tree):对于一颗二叉树来说,如果每个节点都有0个或2个子节点(不能只有1个子节点),那么这颗二叉树就是满二叉树。换句话说,在满二叉树中,除了叶子节点外,每个节点都有两个子节点。
🏳️🌈构建二叉树
构建二叉树有多种方法,其中最基本的方法包括使用递归和队列两种方式。下面我为你介绍这两种方式的实现方法。
🔯使用递归构建二叉树
使用递归方式构建二叉树需要先确定好递归函数的参数和返回值:
- 参数:该节点的值
- 返回值:构建好的节点
首先,我们需要定义节点类:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
接下来,我们使用递归方法来构建二叉树:
def build_tree_by_recursion(preorder, inorder):
if not preorder or not inorder:
return None
# 通过前序遍历确定二叉树的根节点
root_value = preorder[0]
root = TreeNode(root_value)
# 在中序遍历中查找根节点,将中序遍历分为左子树和右子树
root_index = inorder.index(root_value)
left_inorder = inorder[:root_index]
right_inorder = inorder[root_index + 1:]
# 在前序遍历中查找左子树和右子树,分别对左右子树递归构建二叉树
left_preorder = preorder[1:1 + len(left_inorder)]
right_preorder = preorder[1 + len(left_inorder):]
root.left = build_tree_by_recursion(left_preorder, left_inorder)
root.right = build_tree_by_recursion(right_preorder, right_inorder)
return root
在上面的代码中,我们使用先序遍历来确定根节点,在中序遍历中找到根节点的位置,然后将中序遍历分为左子树和右子树,在先序遍历中找到左子树和右子树,分别递归构建左右子树。
使用上面的代码我们可以构建以下二叉树:
构建代码如下:
preorder = [1, 2, 4, 5, 3, 6, 7]
inorder = [4, 2, 5, 1, 6, 3, 7]
root = build_tree_by_recursion(preorder, inorder)
🔯使用队列构建二叉树
使用队列构建二叉树需要先定义好节点类,然后使用队列按照层级遍历的方式逐个节点构建二叉树:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def build_tree_by_queue(values):
if not values:
return None
# 使用队列来存储节点
queue = []
# 根节点
root = TreeNode(values[0])
queue.append(root)
# 循环构建二叉树
i = 1
while i < len(values):
# 取出队列中最先进入队列的节点
parent = queue.pop(0)
# 构建当前节点的左子树
left_value = values[i]
if left_value is not None:
node = TreeNode(left_value)
parent.left = node
queue.append(node)
i += 1
# 构建当前节点的右子树
if i < len(values):
right_value = values[i]
if right_value is not None:
node = TreeNode(right_value)
parent.right = node
queue.append(node)
i += 1
return root
在上面的代码中,我们首先定义了一个队列来按照层级遍历存储每个节点。然后从根节点开始遍历每个节点,先构建其左子树,再构建其右子树。
使用上面的代码我们可以构建以下二叉树:
🏳️🌈遍历二叉树
遍历二叉树是指按照一定的规则访问二叉树中的每个节点,常见的遍历方式包括先序遍历、中序遍历和后序遍历。下面我会依次介绍这三种遍历方式的实现方法。
二叉树示例:
☸️先序遍历(Preorder Traversal)
先序遍历的访问顺序是:根节点 -> 左子树 -> 右子树。
递归实现先序遍历:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def preorder_traversal(root):
if root is None:
return
print(root.value) # 访问根节点
preorder_traversal(root.left) # 遍历左子树
preorder_traversal(root.right) # 遍历右子树
# 创建一个二叉树示例
root = TreeNode('A')
root.left = TreeNode('B')
root.right = TreeNode('C')
root.left.left = TreeNode('D')
root.left.right = TreeNode('E')
# 执行先序遍历
print("先序遍历结果:")
preorder_traversal(root)
运行以上代码,将会按照先序遍历的顺序打印出二叉树节点的值:
先序遍历结果:
A
B
D
E
C
☸️中序遍历(Inorder Traversal)
中序遍历的访问顺序是:左子树 -> 根节点 -> 右子树。
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def inorder_traversal(root):
if root is None:
return
inorder_traversal(root.left) # 遍历左子树
print(root.value) # 访问根节点
inorder_traversal(root.right) # 遍历右子树
# 创建一个二叉树示例
root = TreeNode('A')
root.left = TreeNode('B')
root.right = TreeNode('C')
root.left.left = TreeNode('D')
root.left.right = TreeNode('E')
# 执行中序遍历
print("中序遍历结果:")
inorder_traversal(root)
运行以上代码,将会按照中序遍历的顺序打印出二叉树节点的值:
中序遍历结果:
D
B
E
A
C
☸️后序遍历(Postorder Traversal)
后序遍历的访问顺序是:
是一种二叉树遍历的方式,遍历顺序为:先遍历左子树,然后遍历右子树,最后访问根节点。
下面是一个二叉树的数据结构示例,包含后序遍历的实现:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def postorder_traversal(root):
if root is None:
return
postorder_traversal(root.left) # 遍历左子树
postorder_traversal(root.right) # 遍历右子树
print(root.value) # 访问根节点
# 创建一个二叉树示例
root = TreeNode('A')
root.left = TreeNode('B')
root.right = TreeNode('C')
root.left.left = TreeNode('D')
root.left.right = TreeNode('E')
# 执行后序遍历
print("后序遍历结果:")
postorder_traversal(root)
运行以上代码,将会按照后序遍历的顺序打印出二叉树节点的值:
后序遍历结果:
D
E
B
C
A
🏳️🌈二叉树插入
- 如果树为空,将新节点作为根节点插入。
- 如果树非空,从根节点开始遍历:
①如果新节点的值小于当前节点的值,并且当前节点的左子节点为空,则将新节点插入作为当前节点的左子节点。
②如果新节点的值小于当前节点的值,并且当前节点的左子节点不为空,则以当前节点的左子节点为根继续遍历左子树,重复上述步骤。
③如果新节点的值大于等于当前节点的值,并且当前节点的右子节点为空,则将新节点插入作为当前节点的右子节点。
④如果新节点的值大于等于当前节点的值,并且当前节点的右子节点不为空,则以当前节点的右子节点为根继续遍历右子树,重复上述步骤。
下面是一个示例代码,演示如何在二叉树中插入节点:
二叉树示例:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert_node(root, value):
if root is None:
return TreeNode(value)
if value < root.value:
root.left = insert_node(root.left, value)
else:
root.right = insert_node(root.right, value)
return root
# 创建一个二叉树示例
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
print("原始二叉树:")
# 遍历二叉树确认当前结构
def inorder_traversal(root):
if root is None:
return
inorder_traversal(root.left)
print(root.value, end=" ")
inorder_traversal(root.right)
inorder_traversal(root)
# 插入新节点5
insert_node(root, 5)
print("\n插入新节点后的二叉树:")
inorder_traversal(root)
运行以上代码,将会得到以下输出:
原始二叉树:
1 2 3 4 7
插入新节点后的二叉树:
1 2 3 4 5 7
🏳️🌈二叉树删除
在二叉树中删除一个节点需要先遍历找到该节点,然后进行以下步骤:
- 如果该节点为叶子节点,直接删除。
- 如果该节点只有一个子节点,将其子节点接到该节点的父节点上。
- 如果该节点有两个子节点,找到该节点右子树的最小值节点,将其值复制到该节点,然后删除该最小值节点。
下面是一个示例代码,演示如何在二叉树中删除节点:
二叉树示例:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def delete_node(root, value):
if root is None:
return root
if value < root.value:
root.left = delete_node(root.left, value)
elif value > root.value:
root.right = delete_node(root.right, value)
else:
if root.left is None:
tmp = root.right
root = None
return tmp
elif root.right is None:
tmp = root.left
root = None
return tmp
else:
tmp = find_min(root.right)
root.value = tmp.value
root.right = delete_node(root.right, tmp.value)
return root
def find_min(root):
while root.left is not None:
root = root.left
return root
# 创建一个二叉树示例
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
print("原始二叉树:")
# 遍历二叉树,确认当前结构
def inorder_traversal(root):
if root is None:
return
inorder_traversal(root.left)
print(root.value, end=" ")
inorder_traversal(root.right)
inorder_traversal(root)
# 删除节点2
delete_node(root, 2)
print("\n删除节点2后的二叉树:")
inorder_traversal(root)
运行以上代码,将会输出以下结果:
原始二叉树:
1 2 3 4 7
删除节点2后的二叉树:
1 3 4 7
🏳️🌈总结和应用
二叉树作为一种基本的数据结构,在计算机科学中有着广泛的应用。它不仅可以用于解决各种问题,如表达式求值、建立决策树等,还可以作为其他复杂数据结构和算法的基础。了解和掌握二叉树的基本概念、性质和操作,对于提高算法效率和解决实际问题具有重要意义。希望通过本文的介绍和程序解析,读者能够更好地理解和应用二叉树这一数据结构。在未来的学习和工作中,读者可以继续探索二叉树的其他应用和优化方法,以应对更为复杂的问题和挑战。