c++中堆排序算法如何实现_c++ heap sort代码【源码】

发布时间 - 2026-01-28 00:00:00    点击率:
堆排序核心是heapify而非完整堆类实现,应优先使用std::make_heap和std::pop_heap原地排序,建堆O(n),需从下标(n/2)-1开始sift_down,且不稳定、缓存不友好。

堆排序的核心是 heapify 而不是手写完整二叉堆类

多数人误以为堆排序必须先实现一个完整的 Heap 类(带 insertextract_max 等),其实 C++ 标准库已提供底层支持,且原地排序只需关注 heapify 过程。关键在于:堆排序本质是「建堆 + 反复弹出最大值」,而建堆可以自底向上用 std::make_heap,或手动实现 sift_down 逻辑。

常见错误现象:std::make_heap 后直接遍历数组,发现顺序不对——因为它是最大堆,顶部是最大值,但整个数组不有序;必须配合 std::pop_heap 把最大值逐步移到末尾。

  • std::make_heap 时间复杂度 O(n),不是 O(n log n);这是很多人忽略的优化点
  • 若用 std::priority_queue 实现,会额外分配内存,失去「原地」优势
  • 手动实现 heapify 时,最后一个非叶子节点下标是 (n / 2) - 1,不是 n / 2

std::make_heapstd::pop_heap 组合实现最简版本

这是最贴近算法导论描述、又避免重复造轮子的做法。它不引入额外容器,只操作原始数组,且可复用标准库的健壮性。

void heap_sort(std::vector& arr) {
    std::make_heap(arr.begin(), arr.end());  // 建最大堆
    for (auto it = arr.end(); it != arr.begin(); --it) {
        std::pop_heap(arr.begin(), it);  // 把堆顶移到 [it-1]
    }
}

注意:std::pop_heap 不删除元素,只是把最大值换到当前范围末尾,然后调整剩余部分为堆。所以循环中 itend() 开始递减,每次缩小堆的范围。

  • 如果传入 std::vector,需确保有随机访问迭代器(满足)
  • 排序后是升序;若要降序,改用 std::less 作为第三个参数(默认是 std::less,即最大堆 → 升序)
  • int* 数组也适用:std::make_heap(ptr, ptr + n)

手动实现 sift_down 时索引边界容易错

当不用标准库、必须手写时,核心是 sift_down 函数:从某节点出发,将其下沉到合适位置。最容易出错的是左右孩子索引计算和越界判断。

假设当前节点下标为 i,则:

  • 左孩子: 2 * i + 1(不是 2 * i,因数组从 0 开始)
  • 右孩子: 2 * i + 2
  • 检查是否越界:必须同时满足 left 和 right ,不能只比 arr.size()
  • 下沉前要先比较左右孩子,选较大者再与父节点交换;否则可能破坏堆性质

建堆阶段必须从最后一个非叶子节点开始倒序调用 sift_down,否则无法保证整体堆结构。这个节点是 (arr.size() / 2) - 1,不是 arr.size() / 2

arr.size() - 1

性能与稳定性:堆排序不适合小数组,也不稳定

堆排序时间复杂度稳定在 O(n log n),但常数因子比快排大;实际中,STL 的 std::sort 通常用 introsort(快排+堆排兜底),而非纯堆排。

  • 对少于 ~32 个元素的数组,插入排序更快;标准库实现通常会切分处理
  • 堆排序不稳定:相等元素的相对位置可能改变,比如用于结构体排序时要注意字段相等性
  • 缓存不友好:sift_down 的跳转访问模式导致 CPU cache miss 高于归并或快排

如果你真需要手写堆排序,优先考虑复用 std::make_heap + std::pop_heap;手动实现只在教学、嵌入式无 STL 或定制比较逻辑时才值得投入。


# c++  # 排序算法  # 标准库  # less  # sort  # 结构体  # 插入排序  # int  # 循环  #   # 算法  # 这是  # 升序  # 大堆  # 而非  # 不稳定  # 移到  # 复用  # 的是  # 不友好  # 也不 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 手机网站制作与建设方案,手机网站如何建设?  Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置  javascript中对象的定义、使用以及对象和原型链操作小结  黑客如何通过漏洞一步步攻陷网站服务器?  高端企业智能建站程序:SEO优化与响应式模板定制开发  Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全  详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点  详解Huffman编码算法之Java实现  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  简单实现Android验证码  php结合redis实现高并发下的抢购、秒杀功能的实例  高端智能建站公司优选:品牌定制与SEO优化一站式服务  网站页面设计需要考虑到这些问题  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  如何用虚拟主机快速搭建网站?详细步骤解析  如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框  Laravel怎么实现API接口鉴权_Laravel Sanctum令牌生成与请求验证【教程】  Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言  绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信  微信推文制作网站有哪些,怎么做微信推文,急?  如何破解联通资金短缺导致的基站建设难题?  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】  Laravel观察者模式如何使用_Laravel Model Observer配置  教学论文网站制作软件有哪些,写论文用什么软件 ?  Windows10如何更改计算机工作组_Win10系统属性修改Workgroup  如何在阿里云域名上完成建站全流程?  微信小程序 闭包写法详细介绍  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  详解阿里云nginx服务器多站点的配置  油猴 教程,油猴搜脚本为什么会网页无法显示?  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  焦点电影公司作品,电影焦点结局是什么?  制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  Laravel如何实现一对一模型关联?(Eloquent示例)  如何在服务器上配置二级域名建站?  如何快速生成凡客建站的专业级图册?  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  如何挑选高效建站主机与优质域名?  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  原生JS实现图片轮播切换效果  Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南  JavaScript模板引擎Template.js使用详解  如何在万网利用已有域名快速建站?  Laravel如何构建RESTful API_Laravel标准化API接口开发指南  如何快速生成专业多端适配建站电话?  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】