1. 基础知识
堆的存储是层序的,1...n 所以序号x对应的左右节点是2*x和2 * x + 1
对堆的常见操作有:
- 插入:heap[++n] = x, up(n)
- 求min:heap[1]
- 删除min: heap[1] = heap[n]; n --; down(1)
- 删除任意一个节点:heap[k] = heap[n], n --, down(k),up(k)只会执行一个
- 修改任意一个节点:heap[k] = x, down(x), up(x)
2. 建堆的复杂度
从倒数第二层也就是n/2处开始往下down,得到s = n/4 * 1 + n / 8 * 2 + n / 16 * 3...也就是o(n)复杂度
如果一个一个往里插入是o(logn)的方式
down需要和左右节点比,up往上只用和父节点比较
3.堆排序
void down(int u)
{
int t = u;
if(u*2 <=siz && h[u*2]<h[t]) t = u*2;//先比较左儿子小
if(u*2 +1<=siz && h[u*2+1]<h[t]) t = u*2+1;//再比较右儿子
if(u != t)//不是三个数里的最小值
{
swap(h[u],h[t]);//交换
down(t);//继续down操作
}
}
void up(int u)
{
while(u/2 && h[u/2] >h[u]) //有父节点且值更小
{
swap(h[u/2],h[u]);
u /=2;
}
}
题目
剑指 Offer 40. 最小的k个数
class Solution {
public:
vector<int> res;
vector<int> arr;
int n;
vector<int> getLeastNumbers(vector<int>& h, int k) {
n = h.size() - 1;
arr = h;
for(int i = n / 2; i >= 0; i --) down(i);
while(k --)
{
res.push_back(arr[0]);
arr[0] = arr[n];
n --;
down(0);
}
return res;
}
void down(int u)
{
int t = u;
if(u * 2 + 1<= n && arr[u * 2 + 1] < arr[t] ) t = u * 2 + 1;
if(u * 2 + 2<= n && arr[u * 2 + 2] < arr[t] ) t = u * 2 + 2;
if(u != t)
{
swap(arr[t], arr[u]);
down(t);
}
}
};
剑指 Offer 41. 数据流中的中位数
class MedianFinder {
public:
/** initialize your data structure here. */
//把数据流用大根堆+小根堆模拟,自然也是排好序的,奇数的话大根堆多1个,也就是让前一半小的都在大根堆里
//每次插入到大根堆里面,和小根堆堆顶比是逆序的话就交换(保证个数),多了就移到小根堆
priority_queue<int> max_heap;
priority_queue<int,vector<int>,greater<int>> min_heap;
MedianFinder() {
}
void addNum(int num) {
max_heap.push(num);
if(min_heap.size() && max_heap.top() > min_heap.top())
{
int m1 = max_heap.top(), m2 = min_heap.top();
max_heap.pop(), min_heap.pop();
min_heap.push(m1), max_heap.push(m2);
}
if(max_heap.size() > min_heap.size() + 1)
{
int m = max_heap.top();
max_heap.pop();
min_heap.push(m);
}
}
double findMedian() {
if((max_heap.size() + min_heap.size()) & 1) return max_heap.top();
else return (max_heap.top() + min_heap.top()) / 2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/