在之前汇总的所有算法 整理汇总各排序算法(用python实现) 的基础上,不断迭代更新使得功能,使得越来越完善.
一.堆排序
python
# 08.1 堆排序
def heapify(arr, n, i):
"""
维护堆的性质
arr: 待排序数组
n: 堆的大小
i: 当前节点索引
"""
largest = i # 初始化最大值为当前节点
l = 2 * i + 1 # 左子节点索引 = 2*i + 1
r = 2 * i + 2 # 右子节点索引 = 2*i + 2
# 如果左子节点存在且大于当前最大值
if l < n and arr[i] < arr[l]:
largest = l
# 如果右子节点存在且大于当前最大值
if r < n and arr[largest] < arr[r]:
largest = r
# 如果最大值不是当前节点
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i] # 交换节点值
heapify(arr, n, largest) # 递归维护子树
def heapSort(arr):
"""
堆排序主函数
arr: 待排序数组
"""
n = len(arr) # 获取数组长度
# 构建最大堆(从最后一个非叶子节点开始)
# 时间复杂度: O(n)
for i in range(n, -1, -1):
heapify(arr, n, i)
# 逐个提取堆顶元素(最大值)
# 时间复杂度: O(n log n)
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 将最大值移到数组末尾
heapify(arr, i, 0) # 维护剩余堆
# 测试数据
arr = [12, 11, 13, 5, 6, 7]
n = len(arr)
# 打印初始序列
print(f"初始序列: {arr}")
print(f"序列长度: {n}\n")
# 打印原始数组
print("原始数组:", end=" ")
for num in arr: print(num, end=" ")
print("\n")
# 执行堆排序
heapSort(arr)
# 打印排序结果
print("堆排序后:", end=" ")
for num in arr: print(num, end=" ")
print()
二.堆排序过程
python
#8.2 堆排序(Heap Sort) - 修正版
def heapify(arr, n, i):
"""
维护堆的性质:以 i 为根的子树是最大堆
:param arr: 待排序数组
:param n: 堆的大小
:param i: 当前节点索引
"""
largest = i # 初始化最大值为根节点
left = 2 * i + 1 # 左子节点
right = 2 * i + 2 # 右子节点
# 如果左子节点存在且大于根节点
if left < n and arr[left] > arr[largest]:
largest = left
# 如果右子节点存在且大于当前最大值
if right < n and arr[right] > arr[largest]:
largest = right
# 如果最大值不是根节点,则交换并递归调整
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def heapSort(arr):
"""
堆排序主函数
:param arr: 待排序数组
"""
n = len(arr)
# 构建最大堆:从最后一个非叶子节点开始,自底向上调整
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
# 一个个取出堆顶元素(最大值),放到末尾
for i in range(n - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0] # 将最大值放到末尾
heapify(arr, i, 0) # 重新调整剩余元素为堆
# 主程序
if __name__ == "__main__":
# 输入数据
arr = [12, 11, 13, 5, 6, 7,8,55,21,45,58]
print("=" * 50)
print(" #08.2 堆排序(Heap Sort)")
print("=" * 50)
print(f"初始序列: {arr}")
print(f"序列长度: {len(arr)}\n")
print("步骤 1:构建最大堆")
print(f"构建前: {arr}")
# 构建堆(为了可视化,我们做个副本)
temp_arr = arr.copy()
n = len(temp_arr)
for i in range(n // 2 - 1, -1, -1):
heapify(temp_arr, n, i)
print(f"构建后: {temp_arr}\n")
print("步骤 2:堆排序过程(逐个提取最大值)")
sorted_arr = arr.copy()
heapSort(sorted_arr)
print(f"排序后: {sorted_arr}")
print("\n" + "=" * 50)
print(" 堆排序完成!")
print("=" * 50)
三.堆排序过程可视化gif展示
python
'''
算法记录部分:在heapify和heap_sort函数中,通过frame_list.append(arr.copy())记录每个关键步骤的数组状态
颜色映射:使用plt.cm.Blues颜色映射,数值越大颜色越深,通过np.linspace(0.3, 1, n)生成渐变色
动画更新:update()函数中同时更新柱子高度、颜色和数值标签位置
中文支持:通过fontproperties='SimHei'和plt.rcParams设置支持中文显示
保存参数:使用writer='pillow'兼容性好,fps=3控制播放速度,dpi=100平衡清晰度和文件大小
'''
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
def heap_sort_visual(arr, ax, title="堆排序过程", save_path="堆排序.gif"):
"""
堆排序可视化核心函数
参数:
arr: 待排序数组
ax: matplotlib坐标轴对象
title: 图表标题(支持中文)
save_path: GIF保存路径
"""
n = len(arr)
frame_list = [] # 用于记录排序过程中的每一步状态
# ================== 堆排序核心算法部分 ==================
def heapify(arr, n, i):
"""维护堆性质的递归函数"""
largest = i # 初始化最大元素为当前节点
l = 2 * i + 1 # 左子节点索引
r = 2 * i + 2 # 右子节点索引
# 记录交换前的状态(关键步骤:添加当前状态到帧列表)
frame_list.append(arr.copy())
# 找出当前节点、左子节点、右子节点中的最大值
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
# 如果最大值不是当前节点,进行交换并递归调整
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
# 记录交换后的状态(关键步骤:添加交换后状态)
frame_list.append(arr.copy())
heapify(arr, n, largest)
def heap_sort():
"""堆排序主函数"""
# 构建最大堆(从最后一个非叶子节点开始)
for i in range(n, -1, -1):
heapify(arr, n, i)
# 逐个提取堆顶元素(最大值)
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 将最大值移到数组末尾
frame_list.append(arr.copy()) # 记录交换后的状态
heapify(arr, i, 0) # 维护剩余堆
heap_sort() # 执行排序
# =====================================================
# ================== 可视化设置部分 ==================
# 坐标轴范围设置
ax.set_xlim(-0.5, n-0.5) # X轴范围(柱子数量)
ax.set_ylim(0, max(arr)*1.1) # Y轴范围(最大数值的1.1倍)
ax.set_title(title, fontsize=16, fontproperties='SimHei') # 支持中文标题
ax.set_xticks([]) # 隐藏X轴刻度
ax.set_yticks([]) # 隐藏Y轴刻度
# 创建颜色映射(数值越大颜色越深)
# 使用Blues颜色映射,从浅蓝(0.3)到深蓝(1)
colors = plt.cm.Blues(np.linspace(0.3, 1, n))
# 创建柱状图(带黑色边框)
bars = ax.bar(range(n), arr, color=colors, edgecolor='black', linewidth=0.5)
# 添加数值标签(初始位置)
offset = 0.3 # 标签与柱子顶部的间距
text_labels = [
ax.text(i, val + offset, str(val),
ha='center', va='bottom',
fontsize=10, fontproperties='SimHei') # 支持中文显示
for i, val in enumerate(arr)
]
# =====================================================
# ================== 动画更新函数 ==================
def update(frame):
"""动画更新函数,每帧调用一次"""
# 更新柱子高度
for i, bar in enumerate(bars):
bar.set_height(frame[i])
# 更新颜色映射(根据当前帧数值重新计算)
norm = plt.Normalize(0, max(frame)) # 归一化数值到[0,1]
colors = plt.cm.Blues(norm(frame)) # 生成颜色
for bar, color in zip(bars, colors):
bar.set_color(color) # 设置柱子颜色
# 更新数值标签位置和内容
for i, text in enumerate(text_labels):
text.set_y(frame[i] + offset) # 更新标签Y位置
text.set_text(str(frame[i])) # 更新标签数值
return bars, text_labels # 返回需要更新的元素
# 创建动画对象(关键参数说明)
ani = animation.FuncAnimation(
fig, # 所在图形
update, # 更新函数
frames=frame_list, # 帧数据列表
interval=800, # 帧间隔(毫秒)
blit=False, # 是否优化绘制(关闭以支持中文)
repeat=False # 是否循环播放
)
# =====================================================
# 保存GIF(关键参数说明)
ani.save(
save_path, # 保存路径
writer='pillow', # 使用Pillow库生成GIF
fps=3, # 帧率(3帧/秒)
dpi=100 # 分辨率
)
return ani
# ================== 使用示例 ==================
if __name__ == "__main__":
# 设置中文字体(避免中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 初始化测试数据
arr = [12, 11, 13, 5, 6, 7, 90, 3, 45, 67]
# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(12, 6))
# 生成并保存动画
ani = heap_sort_visual(
arr,
ax,
title="堆排序动态演示", # 中文标题
save_path="./堆排序动画.gif" # 自定义保存路径
)
plt.tight_layout() # 自动调整布局
plt.show()
精简版如下,后续可以按这模板来修改对应的排序算法相关代码:
python
#8.3 堆排序生成更新数值显示变化的gif图,并自定义保存到为位置 (精简版)
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
def heap_sort_visual(arr, ax, title="堆排序过程", save_path="堆排序.gif"):
n = len(arr)
frame_list = [] # 记录每一步的数组状态
def heapify(arr, n, i):
largest = i
l = 2 * i + 1
r = 2 * i + 2
# 记录交换前的状态
frame_list.append(arr.copy())
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
# 记录交换后的状态
frame_list.append(arr.copy())
heapify(arr, n, largest)
def heap_sort():
# 构建最大堆
for i in range(n, -1, -1):
heapify(arr, n, i)
# 逐个提取元素
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
frame_list.append(arr.copy())
heapify(arr, i, 0)
heap_sort()
# 图形初始化设置
ax.set_xlim(-0.5, n-0.5)
ax.set_ylim(0, max(arr)*1.1)
ax.set_title(title, fontsize=16, fontproperties='SimHei')
ax.set_xticks([])
ax.set_yticks([])
# 创建颜色映射(数值越大颜色越深)
colors = plt.cm.Blues(np.linspace(0.3, 1, n))
bars = ax.bar(range(n), arr, color=colors, edgecolor='black', linewidth=0.5)
# 添加数值标签
offset = 0.3
text_labels = [
ax.text(i, val+offset, str(val), ha='center', va='bottom',
fontsize=10, fontproperties='SimHei')
for i, val in enumerate(arr)
]
def update(frame):
# 更新柱子高度和颜色
for i, bar in enumerate(bars):
bar.set_height(frame[i])
norm = plt.Normalize(0, max(frame))
colors = plt.cm.Blues(norm(frame))
for bar, color in zip(bars, colors):
bar.set_color(color)
# 更新数值标签
for i, text in enumerate(text_labels):
text.set_y(frame[i]+offset)
text.set_text(str(frame[i]))
return bars, text_labels
# 创建动画
ani = animation.FuncAnimation(
fig, update, frames=frame_list,
interval=800, blit=False, repeat=False
)
# 保存GIF(使用pillow writer)
ani.save(save_path, writer='pillow', fps=3, dpi=100)
return ani
# 使用示例
if __name__ == "__main__":
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 初始化数据和图形
arr = [12, 11, 13, 5, 6, 7, 90, 3, 45, 67]
fig, ax = plt.subplots(figsize=(12, 6))
# 生成并保存动画
ani = heap_sort_visual(
arr, ax,
title="堆排序_动态过程演示",
save_path="./堆排序演示.gif" # 自定义保存路径
)
plt.tight_layout()
plt.show()
整理不易,诚望各位看官点赞 收藏 评论 予以支持,这将成为我持续更新的动力源泉。若您在阅览时存有异议或建议,敬请留言指正批评,让我们携手共同学习,共同进取,吾辈自当相互勉励!