算法实现迭代2_堆排序

在之前汇总的所有算法 整理汇总各排序算法(用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()

整理不易,诚望各位看官点赞 收藏 评论 予以支持,这将成为我持续更新的动力源泉。若您在阅览时存有异议或建议,敬请留言指正批评,让我们携手共同学习,共同进取,吾辈自当相互勉励!

相关推荐
天桥下的卖艺者6 小时前
R语言手搓一个计算生存分析C指数(C-index)的函数算法
c语言·算法·r语言
Espresso Macchiato6 小时前
Leetcode 3715. Sum of Perfect Square Ancestors
算法·leetcode·职场和发展·leetcode hard·树的遍历·leetcode 3715·leetcode周赛471
总有刁民想爱朕ha6 小时前
Python自动化从入门到实战(24)如何高效的备份mysql数据库,数据备份datadir目录直接复制可行吗?一篇给小白的完全指南
数据库·python·自动化·mysql数据库备份
草莓熊Lotso6 小时前
《C++ Stack 与 Queue 完全使用指南:基础操作 + 经典场景 + 实战习题》
开发语言·c++·算法
孤客网络科技工作室6 小时前
Python - 100天从新手到大师:第五十七天获取网络资源及解析HTML页面
开发语言·python·html
敲上瘾6 小时前
单序列和双序列问题——动态规划
c++·算法·动态规划
太过平凡的小蚂蚁7 小时前
策略模式:让算法选择像点菜一样简单
算法·策略模式
帅大大的架构之路7 小时前
高级篇:Python脚本(101-150)
开发语言·python
liweiweili1267 小时前
Django中处理多数据库场景
数据库·python·django