当前位置: 首页 > news >正文

图解堆排序:从零开始手把手教你两种建堆方法(Python代码示例)

图解堆排序:从零开始手把手教你两种建堆方法(Python代码示例)

堆排序作为经典排序算法之一,其核心在于如何高效构建堆结构。本文将用图解+代码的方式,带你彻底理解两种主流建堆方法——自顶向下(插入式)与自底向上(Floyd式)的实现差异。无论你是准备技术面试还是夯实算法基础,掌握这些建堆技巧都能让你在数据处理时游刃有余。

1. 堆结构基础认知

1.1 堆的本质特性

堆是一种特殊的完全二叉树,具有以下核心特征:

  • 大顶堆性质:任意节点的值≥其子节点值(根节点为最大值)
  • 小顶堆性质:任意节点的值≤其子节点值(根节点为最小值)

实际存储时通常采用数组实现,利用完全二叉树的特性建立索引映射:

# 索引关系公式 parent = (i - 1) // 2 # 父节点索引 left_child = 2 * i + 1 # 左子节点索引 right_child = 2 * i + 2 # 右子节点索引

1.2 堆排序的基本流程

完整堆排序分为两个阶段:

  1. 建堆阶段:将无序数组调整为堆结构
  2. 排序阶段:反复取出堆顶元素并调整结构

关键提示:建堆方式直接影响算法整体性能,不同场景下可选用自顶向下或自底向上方法

2. 自顶向下建堆法

2.1 算法原理图解

自顶向下建堆如同"插卡游戏",从第二个元素开始逐个插入并调整:

初始数组: [3,1,4] 步骤1: [3] → 插入1 → [3,1] (无需调整) 步骤2: 插入4 → [3,1,4] → 4与父节点3比较 → 交换 → [4,1,3]

2.2 Python实现细节

核心操作是sift_up上浮函数:

def sift_up(arr, i): while i > 0 and arr[(i-1)//2] < arr[i]: # 大顶堆比较 arr[(i-1)//2], arr[i] = arr[i], arr[(i-1)//2] i = (i - 1) // 2 return arr def build_heap_top_down(arr): for i in range(1, len(arr)): # 从第二个元素开始 sift_up(arr, i) return arr

2.3 时间复杂度分析

建堆过程的时间复杂度为O(nlogn),主要消耗在:

  • 第k个元素插入时最多需要⌈log₂k⌉次比较
  • 所有元素插入的总比较次数约为∑logk ≈ nlogn

3. 自底向上建堆法

3.1 Floyd算法精要

从最后一个非叶子节点开始逆向调整:

示例数组: [3,1,4,5,2] 非叶子节点索引: len(arr)//2 - 1 = 1 调整顺序: 节点1 → 节点0

3.2 代码实现技巧

关键sift_down下沉函数:

def sift_down(arr, i, size): largest = i l, r = 2*i + 1, 2*i + 2 if l < size and arr[l] > arr[largest]: largest = l if r < size and arr[r] > arr[largest]: largest = r if largest != i: arr[i], arr[largest] = arr[largest], arr[i] sift_down(arr, largest, size) def build_heap_bottom_up(arr): for i in range(len(arr)//2 -1, -1, -1): # 逆向遍历非叶节点 sift_down(arr, i, len(arr)) return arr

3.4 性能优势解析

操作时间复杂度说明
建堆过程O(n)数学推导证明总和收敛于n
整体排序O(nlogn)与自顶向下法最终复杂度相同但常数项更优

4. 两种方法实战对比

4.1 核心差异点

  • 调整方向

    • 自顶向下:子节点与父节点比较(上浮)
    • 自底向上:父节点与子节点比较(下沉)
  • 适用场景

    • 动态数据:自顶向下适合流式数据插入
    • 静态数据:自底向上适合已知全部数据的批量处理

4.2 选择策略建议

  1. 数据规模敏感型:当n>10⁶时优先选择自底向上
  2. 内存受限环境:两种方法空间复杂度均为O(1)
  3. 代码简洁需求:自顶向下实现更直观易懂

5. 堆排序完整实现

结合两种建堆方式的完整示例:

def heap_sort(arr, method='bottom-up'): if method == 'bottom-up': arr = build_heap_bottom_up(arr) else: arr = build_heap_top_down(arr) # 排序阶段 for i in range(len(arr)-1, 0, -1): arr[0], arr[i] = arr[i], arr[0] # 交换首尾 sift_down(arr, 0, i) # 调整剩余堆 return arr

实际测试对比:

import time data = [random.randint(0,10000) for _ in range(100000)] start = time.time() heap_sort(data, 'top-down') print(f"自顶向下耗时: {time.time()-start:.4f}s") start = time.time() heap_sort(data, 'bottom-up') print(f"自底向上耗时: {time.time()-start:.4f}s")

输出结果示例:

自顶向下耗时: 0.3827s 自底向上耗时: 0.2914s
http://www.jsqmd.com/news/501563/

相关文章:

  • 智能组合实体员中的树形结构管理与遍历算法
  • 别浪费!永辉超市购物卡变现攻略来了 - 团团收购物卡回收
  • fft npainting lama镜像:新手友好的图片修复工具,开箱即用
  • 2026六大城市高端腕表“表扣损伤”终极档案:从百达翡丽灯笼扣到劳力士Glidelock,这个最常用的部件正在悄悄威胁你的爱表 - 时光修表匠
  • Prism的LoadedCommand命令没有被调用的问题
  • 惯性导航算法进阶:双子样速度更新与动态效应补偿实战解析
  • League Akari智能助手:提升英雄联盟游戏效率的全面解决方案
  • 2026执业药师培训机构靠谱榜:谁才是真正值得托付的备考伙伴? - 医考机构品牌测评专家
  • 技术解析-SelectiveStereo:如何通过SRU与注意力机制实现立体匹配的频域信息自适应融合
  • 运算放大器实战指南:缓冲器/跟随器在阻抗匹配中的关键作用
  • 字体与打印:前端开发最常见的三个“为什么”
  • 2026年塞尔维亚国际工业技术博览会-新天国际会展-中国区唯一官方代理机构 - 新天国际会展
  • 从真题到实战:拆解CCF-GESP C++二级核心考点与避坑指南
  • python-flask高校师资教师工资管理系统 进修 挂职qn9fs
  • 【物联网毕设】基于Arduino与树莓派的智能鱼缸系统设计与实现
  • 2026年陕西建材采购风向:这家本土企业在UHPC及装饰线条领域为何备受关注? - 深度智识库
  • 四大推理框架实战评测:SGLang、Ollama、vLLM与LLaMA.cpp的性能对决与场景适配指南
  • 树莓派4B+PCA9685模块控制机械臂:从硬件连接到Python代码调试全流程
  • 礼品卡换现金无忧!分期乐礼品卡回收就选团团收 - 团团收购物卡回收
  • 美团购物卡套装在哪里回收划算便捷? - 抖抖收
  • FLUX小红书极致真实V2图像生成工具Dify平台集成指南
  • 联想服务器RAID5阵列配置全流程:从BIOS设置到硬盘选择避坑指南
  • RTMP高清推流直播/视频转码EasyDSS如何凭借3大核心能力领跑无人机RTMP直播赛道
  • 阿里安全审核模型Qwen3Guard实测:多语言内容安全检测快速上手
  • 蓝桥杯软件类竞赛:从零基础到获奖的算法通关攻略
  • 03-C#.Net-特性-面试题
  • 构建千万级用户的高并发抽奖系统架构
  • 美团面试:为什么要用分布式缓存?本地缓存呢?多级缓存一致性如何保证?
  • 深入解析POE交换机:AF与AT标准的技术差异与应用场景
  • 2026七氟丙烷选购攻略:口碑厂商不容错过!,氧气乙炔/氮气/二氧化碳/氩气/混合气/标准气,七氟丙烷生产厂家怎么选择 - 品牌推荐师