news 2026/5/12 12:04:40

堆排序:核心原理与实战优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
堆排序:核心原理与实战优化

一、堆排序核心知识点

1. 底层基础

  • 基于完全二叉树,用数组顺序存储
  • 下标规则(从 0 开始):
    • 父节点:\((i-1)/2\)
    • 左孩子:\(2i+1\)
    • 右孩子:\(2i+2\)
  • 堆分两种:
    • 大根堆:父 ≥ 孩子 → 升序排序用
    • 小根堆:父 ≤ 孩子 → 降序 / TopK 用

2. 核心思想

  1. 把原数组原地构建成大根堆
  2. 堆顶(最大值)和末尾元素交换,最大值落到有序末尾
  3. 缩小堆范围,对新堆顶做向下调整(堆化)
  4. 重复交换 + 堆化,直到整体有序

3. 复杂度

  • 时间:平均 / 最好 / 最坏都是 \(O(n\log n)\)
  • 空间:\(O(1)\) 原地排序,仅常数临时变量
  • 稳定性:不稳定排序

4. 关键概念

  • 堆化 shiftDown:某节点不满足堆性质,向下逐层调整
  • 建堆:从最后一个非叶子节点倒着往前逐个堆化最后一个非叶子节点下标:\(n/2 - 1\)

5. 特点 & 面试考点

  1. 不受初始序列影响,稳定保持 \(O(n\log n)\)
  2. 原地排序,不额外开数组
  3. 不稳定,相同元素相对位置会变
  4. 适合海量数据 TopK、海量排序
  5. 缺点:缓存局部性不如快排,常数略大

6. 优化点

  • 建堆从后往前非叶子节点开始,不用处理叶子
  • 排序每次只堆化堆顶,不用重新建堆

二、堆排序完整源码(C++ 升序 大根堆)

cpp

#include <iostream> #include <vector> #include <algorithm> using namespace std; // 向下堆化:把以 idx 为根的子树调成大根堆 void shiftDown(vector<int>& arr, int idx, int len) { int parent = idx; int child = 2 * parent + 1; // 左孩子 while (child < len) { // 选左右孩子中更大的 if (child + 1 < len && arr[child + 1] > arr[child]) child++; if (arr[parent] >= arr[child]) break; // 已经满足大根堆,无需调整 swap(arr[parent], arr[child]); parent = child; child = 2 * parent + 1; } } // 堆排序主逻辑 void heapSort(vector<int>& arr) { int n = arr.size(); // 1. 建大根堆:从最后一个非叶子节点往前堆化 for (int i = n / 2 - 1; i >= 0; --i) { shiftDown(arr, i, n); } // 2. 依次交换堆顶到末尾 + 重新堆化 for (int i = n - 1; i > 0; --i) { swap(arr[0], arr[i]); // 堆顶最大值放末尾 shiftDown(arr, 0, i); // 缩小范围,调整堆顶 } } int main() { vector<int> arr = {4, 6, 8, 5, 9, 1, 3, 2, 7}; heapSort(arr); for (int x : arr) cout << x << " "; return 0; }

三、小根堆版本(降序排序)

只改shiftDown比较逻辑即可:

cpp

void shiftDownMin(vector<int>& arr, int idx, int len) { int parent = idx; int child = 2 * parent + 1; while (child < len) { if (child + 1 < len && arr[child + 1] < arr[child]) child++; if (arr[parent] <= arr[child]) break; swap(arr[parent], arr[child]); parent = child; child = 2 * parent + 1; } } void heapSortDesc(vector<int>& arr) { int n = arr.size(); for (int i = n / 2 - 1; i >= 0; --i) shiftDownMin(arr, i, n); for (int i = n - 1; i > 0; --i) { swap(arr[0], arr[i]); shiftDownMin(arr, 0, i); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 12:03:34

Fast-GitHub:国内开发者必备的GitHub网络优化解决方案

Fast-GitHub&#xff1a;国内开发者必备的GitHub网络优化解决方案 【免费下载链接】Fast-GitHub 国内Github下载很慢&#xff0c;用上了这个插件后&#xff0c;下载速度嗖嗖嗖的~&#xff01; 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub Fast-GitHub是一…

作者头像 李华
网站建设 2026/5/12 12:01:38

Dify-WebUI:开源桌面客户端,解锁Dify深度对话与个性化定制

1. 项目概述&#xff1a;一个为Dify而生的现代化桌面对话前端如果你正在使用Dify来构建自己的AI应用&#xff0c;但总觉得官方的Web界面在深度对话、个性化定制或者本地部署的体验上差点意思&#xff0c;那么这个名为Dify-WebUI的开源项目&#xff0c;很可能就是你一直在找的“…

作者头像 李华
网站建设 2026/5/12 12:00:50

3大突破性功能:kill-doc如何重新定义文档下载体验

3大突破性功能&#xff1a;kill-doc如何重新定义文档下载体验 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档&#xff0c;但是相关网站浏览体验不好各种广告&#xff0c;各种登录验证&#xff0c;需要很多步骤才能下载文档&#xff0c;该脚本就是为了解决您…

作者头像 李华
网站建设 2026/5/12 11:59:41

从LeNet5结构解析到现代轻量化网络设计启示

1. LeNet5&#xff1a;卷积神经网络的起点 1998年Yann LeCun提出的LeNet5&#xff0c;是第一个成功应用于手写数字识别的卷积神经网络。这个看似简单的网络结构&#xff0c;奠定了现代深度学习的基石。我第一次复现这个网络时&#xff0c;发现它的设计处处透露着精妙。比如输入…

作者头像 李华