堆(heap)在c++中的实现
不少涉及最大最小值的算法都会用到堆(优先队列),今个做中位数的时候用到了堆,就整理下堆的用法及实现。
一. 堆
在逻辑上可以看作是完全二叉树的一种,其特点是堆中某个结点的值总是不大于或不小于其父结点的值。最常用的于堆排序。堆排序优点在于能够快速获取最大(最小)的k个值。堆在存储上可以通过一维数组(优先队列)
来实现。
二.堆的操作
堆的操作一般包括:查找顶元素,删除元素,插入元素。此外还包括堆排序
一维数组表示的完全二叉树的以下特性可以帮助我们更快的调整堆
- 索引为p的结点的左孩子的索引为p*2+ 1
- 索引为p的结点的右孩子的索引为p *2+ 2
- 索引为p的结点的父亲的索引为(p-1)/ 2
查找:直接返回堆顶的值就行,即返回vector a[0],时间复杂度为O(1)。
删除:先用队尾的元素替换掉要删除的元素,然后从该元素的子结点中选择较大(较小)的值和其比较,循环往复,直到满足堆的性质。时间复杂度为O(logN)
h[i] = h[h.size() - 1];
h.pop_back();
while (i * 2 + 2 < h.size() && (h[i * 2 + 1] > h[i] || h[i * 2 + 2] > h[i])) {
int w;
if (h[i * 2 + 1] > h[i * 2 + 2])
w = i * 2 + 1;
else
w = i * 2 + 2;
int m = max(h[i * 2 + 1], h[i * 2 + 2]);
int t = m;
m = h[i];
h[i] = t;
i = w;
}
if (i * 2 + 1 < h.size() && h[i * 2 + 1] > h[i])
{
int t = h[i * 2 + 1];
h[i*2+1] = h[i];
h[i] = t;
}
插入:将元素插入到队尾,从下到上的调整堆就好。时间复杂度O(logn)
h.push_back(num);
int l1=(h.size()+1)/2-1;
int l2=h.size();
while(l1>=0&&num<h[l1]){
int t=h[l1];
h[l1]=h[l2];
h[l2]=t;
l2=l1;
l1=(l2+1)/2-1;
}
堆排序:按照数组的次序填入完全二叉树,再从倒数第一个不是叶子节点的节点开始,一个个地看是不是要向下调整,一直下调到不能再调。时间复杂度O(nlogn)
void Adjust(int low,int high){
int i = low;
int j = i*2;
while(j<=n){
if(j+1<=n&&heap[j+1]>heap[j]){
j = j+1;
}
if(heap[i]<heap[j]){
swap(heap[i],heap[j]);
i = j;
j = i*2;
}else break;
}
}
三.stl中的实现
STL中定义的模板类为priority_queue,其定义如下,其中的排序操作可以通过重载运算符实现。
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> >
STL中的操作包括以下五个,其中并没有实现任意位置删除,而是只能删除堆顶的元素。
- bool empty():如果优先队列为空返回 true,否则返回false。
- int size():返回优先队列中元素数量。
- void push(const T&. t):把t元素压入优先队列。
- void pop():优先队列非空情况下,删除优先级最高元素。
- T&. top():优先队列非空情况下,返回优先级最高元素的引用。
2023-03-20 21:06:48
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)