网站首页 > 文章精选 正文
堆排序是一种基于堆这种特殊结构的选择排序。常见于不允许使用额外空间(in-place)的场景,且性能稳定为 O(n log n)。
它的过程可以非常简单地概括为四步:
我的理解(堆排序核心步骤)
- 建最大堆(或最小堆)
- 所有数据先变成一个“堆”(最大堆适用于升序)
- 交换顶底元素
- 堆顶是最大元素,把它跟堆尾交换,最大元素被“摘出来了”
- 干掉底部元素
- 把末尾元素从“堆”里踢出去,相当于缩小堆的尺寸,代表它已经排序完了
- 重复前面步骤
- 对剩下的堆重新调整(堆化),最大值又回到堆顶,继续摘
一直重复,直到堆中只剩一个元素——排序完成!
图示演示(以最大堆升序为例)
初始数组:[4, 10, 3, 5, 1]
步骤如下:
Step 1: 构建最大堆
[10, 5, 3, 4, 1]
Step 2: 交换堆顶与堆尾 → [1, 5, 3, 4, 10]
剔除堆尾(10) → 只对前 4 个元素堆化
Step 3: 堆化 → [5, 4, 3, 1, 10]
Step 4: 交换堆顶与堆尾 → [1, 4, 3, 5, 10]
剔除 5 → 堆化前 3 个
...
最终结果:`[1, 3, 4, 5, 10]`
C# 实现(按步骤清晰注释)
public class HeapSorter
{
public static void HeapSort(int[] arr)
{
int n = arr.Length;
// 1. 建最大堆
for (int i = n / 2 - 1; i >= 0; i--)
Heapify(arr, n, i);
// 2. 顶底交换 + 3. 干掉底部元素 + 4. 重复
for (int i = n - 1; i > 0; i--)
{
// 交换堆顶和堆尾
(arr[0], arr[i]) = (arr[i], arr[0]);
// 调整剩余部分为最大堆(i 是新堆的大小)
Heapify(arr, i, 0);
}
}
// 调整以 root 为根的子树,使其成为最大堆
private static void Heapify(int[] arr, int heapSize, int root)
{
int largest = root;
int left = 2 * root + 1;
int right = 2 * root + 2;
if (left < heapSize && arr[left] > arr[largest])
largest = left;
if (right < heapSize && arr[right] > arr[largest])
largest = right;
if (largest != root)
{
(arr[root], arr[largest]) = (arr[largest], arr[root]);
Heapify(arr, heapSize, largest);
}
}
}
Go 实现(同样思路)
package main
import (
"fmt"
)
func heapSort(arr []int) {
n := len(arr)
// 1. 建最大堆
for i := n/2 - 1; i >= 0; i-- {
heapify(arr, n, i)
}
// 2. 顶底交换 + 3. 干掉底部 + 4. 重复
for i := n - 1; i > 0; i-- {
arr[0], arr[i] = arr[i], arr[0] // 交换堆顶和堆尾
heapify(arr, i, 0) // 堆化剩下的部分
}
}
func heapify(arr []int, heapSize int, root int) {
largest := root
left := 2*root + 1
right := 2*root + 2
if left < heapSize && arr[left] > arr[largest] {
largest = left
}
if right < heapSize && arr[right] > arr[largest] {
largest = right
}
if largest != root {
arr[root], arr[largest] = arr[largest], arr[root]
heapify(arr, heapSize, largest)
}
}
func main() {
arr := []int{4, 10, 3, 5, 1}
fmt.Println("原始数组:", arr)
heapSort(arr)
fmt.Println("排序后:", arr)
}
总结一句话:
堆排序本质上是一个“摘最大值放到底部 + 重建最大堆”的过程,构造最大堆就是在为这个摘果子流程做准备。
延伸阅读
如果你用的是最小堆,也可以实现降序排序
PriorityQueue<T> 是堆结构的实际应用
实时 TopK、图论中的 Dijkstra、调度算法都基于堆
猜你喜欢
- 2025-07-08 Rust编程语言之父都在用什么工具(rust编程语言怎么样)
- 2025-07-08 go语言中性能分析工具pprof使用心得
- 2025-07-08 爱上开源之golang入门至实战第三章-内存逃逸
- 2025-07-08 GO 编程:Golang的协程调度器原理及GMP设计思想
- 2025-07-08 Go语言核心36讲(新年彩蛋)--学习笔记
- 2025-07-08 c语言中堆和栈的区别(c语言堆和栈的概念和区别)
- 2025-07-08 Go 语言内存管理(一):系统内存管理
- 2025-07-08 深入解读Raft算法与etcd工程实现(etcd raft库原理)
- 2025-07-08 Go语言中的性能考虑和优化(go语言的效率)
- 2025-07-08 高性能 Go 的 6 个技巧 — Go 高级主题
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)