堆排序以及C++实现
参考博客:
https://www.cnblogs.com/lanhaicode/p/10546257.html
https://www.cnblogs.com/woxiaosade/p/10628388.html
一. 堆的概念
堆是一种非线性结构,可以把堆看作一个数组,也可以被看作一个完全二叉树,通俗来讲堆其实就是利用完全二叉树的结构来维护的一维数组
按照堆的特点可以把堆分为大顶堆和小顶堆
大顶堆:每个结点的值都大于或等于其左右孩子结点的值
小顶堆:每个结点的值都小于或等于其左右孩子结点的值
(堆的这种特性非常的有用,堆常常被当做优先队列使用,因为可以快速的访问到“最重要”的元素)
我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
二. 创建堆
下为从一个数组创建一个大顶堆的例子:
给定数组{0,1,2,3,4,5,6,7,8,9},先依次创建一个完全二叉树:
然后,大顶堆从底层向上层搜索,3[7][8]这个节点因为8最大,交换8和3,同理交换4和9
再然后,交换倒数第二层的元素1和9,6和2,交换完,看下一层,发现1和4需要交换:
然后,检查最上层,交换0和9,再看第二层,交换0和8,然后检查最后一层,0和7需要交换
自此,一个大顶堆构建完成,顺便分享在线画二叉树的网站:
C++中,std::make_leap() 可以用来创建堆,默认第三个参数为 std::less<int>(),即创建大顶堆,改成std::greater<int>()可以创建小顶堆
示例:
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 int main() 7 { 8 vector<int> q; 9 for (int i = 0; i < 10; i++) { 10 q.push_back(i); 11 } 12 make_heap(q.begin(), q.end(), less<int>()); 13 for (int i = 0; i < q.size(); i++){ 14 cout << q[i] << " "; 15 } 16 cout << endl; 17 return 0; 18 } 19 20 //Output: 9 8 6 7 4 5 2 0 3 1
三. C++中堆的其它操作
std::pop_heap
用于将堆的第零个元素与最后一个元素交换位置,然后针对前n - 1个元素调用make_heap()函数,它也有三个参数,参数意义与make_heap()相同,第三个参数应与make_heap时的第三个参数保持一致。
注意:pop_heap()函数,只是交换了两个数据的位置,如果需要弹出这个数据,请记得在pop_heap()后加上q.pop_back();
示例:
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 int main() 7 { 8 vector<int> q; 9 for (int i = 0; i < 10; i++) { 10 q.push_back(i); 11 } 12 make_heap(q.begin(), q.end(), less<int>()); 13 pop_heap(q.begin(), q.end(), less<int>()); 14 for (int i = 0; i < q.size(); i++) { 15 cout << q[i] << " "; 16 } 17 cout << endl; 18 return 0; 19 } 20 21 //Output: 8 7 6 3 4 5 2 0 1 9
std::push_heap
push_heap()用于把数据插入到堆中,它也有三个参数,其意义与make_heap()的相同,第三个参数应与make_heap时的第三个参数保持一致。
在使用push_heap()前,请确保已经把数据通过q.push_back()传入q中,而不是在push_heap()后再使用q.push_back(t)!!
示例:
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 int main() 7 { 8 vector<int> q; 9 for (int i = 0; i < 10; i++) { 10 q.push_back(i); 11 } 12 make_heap(q.begin(), q.end(), less<int>()); 13 q.push_back(10); 14 push_heap(q.begin(), q.end(), less<int>()); 15 for (int i = 0; i < q.size(); i++) { 16 cout << q[i] << " "; 17 } 18 cout << endl; 19 return 0; 20 }
插入后结果变为:
10 9 6 7 8 5 2 0 3 1 4
std::sort_heap
将heap进行堆排序
上例排序后结果为:1 2 3 4 5 6 7 8 9
堆排序的原理:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值,如此反复执行,便能得到一个有序序列了。
pseudo code:
升序----使用大顶堆
降序----使用小顶堆
四. 典型应用
经典例题:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
利用堆顶最大的原理解决这个问题。
1 vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { 2 int len=input.size(); 3 if(k<1||k>len) return vector<int>(); 4 5 vector<int> res(input.begin(),input.begin()+k);//左闭右开input.begin()+k是res.end()的位置 6 //建堆(默认最大堆) 7 make_heap(res.begin(),res.end()); 8 9 for(int i=k;i<len;i++) 10 { 11 if(input[i]<res[0]) 12 { 13 //先pop,然后在容器中删除 14 pop_heap(res.begin(),res.end()); 15 res.pop_back(); 16 //先在容器中加入,再push 17 res.push_back(input[i]); 18 push_heap(res.begin(),res.end()); 19 } 20 } 21 //使其从小到大输出 22 sort_heap(res.begin(),res.end()); 23 24 return res; 25 26 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具