052.堆结构与堆排序
堆结构
编号
在数组上模拟完全二叉树
对于下标为i的节点
父节点为 (i-1)/2
左孩子为 2*i + 1
右孩子为 2*i + 2
根节点编号为0,这样就会发现根节点的父节点就是(0-1)/2 = 0自己
大根堆,小根堆
大根堆的每一个子结构的最大值都在堆顶
小根堆的每一个子结构的最小值都在堆顶
下面以大根堆为例,用数组实现堆结构核心函数
sink(下沉),swim(上浮)
// arr[] : 原始数组
// i : 操作节点编号
void swim(int arr[],int i){
while(arr[i]>arr[(i-1)/2]){
swap(arr[i],swap((i-1)/2));
i=(i-1)/2;
}
}
// arr[] : 原始数组
// i : 操作节点编号
// siz : 堆的大小
void sink(int arr[],int i,int siz){
int l=2*i+1;
while(l<siz){
int best=l+1<siz&&arr[l+1]>arr[l]?l+1:l;
if(arr[best]<=arr[i])return;
swap(arr[i],arr[best]);
i=best;
l=i*2+1;
}
}
堆排序
我们可以在一个数组上原地建堆,实现O(N*logN)原地排序
class Solution {
void sink(vector<int>&nums,int i,int siz){
int l=i*2+1;
while(l<siz){
int best=l+1<siz&&nums[l+1]>nums[l]?l+1:l;
if(nums[best]<=nums[i])return;
swap(nums[best],nums[i]);
i=best;
l=i*2+1;
}
}
public:
vector<int> sortArray(vector<int>& nums) {
int n=nums.size();
//自底向上原地建堆
for(int i=n-1;i>=0;--i){
sink(nums,i,n);
}
//将最大值搬到堆的(末位)右下角,并逐渐缩小堆的siz
int siz=n;
while(siz){
swap(nums[0],nums[siz-1]);
siz--;
sink(nums,0,siz);
}
return nums;
}
};
priority_queue
vector除外,体感上priority_queue和unordered_map是我使用最多的容器
priority_queue就是用堆实现的,在cpp中默认是大根堆
实现O(logN)的push(),pop()操作
O(1)的top()查看堆顶
可以通过
priority_queue<int,vector<int>,greater<int>>pq;
获得小根堆
也可以这样实现自定义比较器
struct edge{
int u;
int v;
int w;
};
auto cmp=[](auto a,auto b){return a.w < b.w;};
priority_queue<edge,vector<edge>,decltype(cmp)>pq(cmp);
习题
合并k个升序链表
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode *dumm=new ListNode(-1);
ListNode *p=dumm;
auto cmp=[](auto a,auto b){return a->val>b->val;};
priority_queue<ListNode*,vector<ListNode*>,decltype(cmp)>pq(cmp);
for(auto list:lists){
if(list!=nullptr)
pq.push(list);
}
while(!pq.empty()){
auto cur=pq.top();
pq.pop();
p->next=cur;
if(cur->next!=nullptr){
pq.push(cur->next);
}
p=p->next;
}
return dumm->next;
}
};
top K 问题
堆里最多只有k个元素,所以复杂度是O(N*logk)
优于直接排序O(N*logN),逊于快速选择算法O(N)
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int,vector<int>,greater<int>>pq;
for(auto x:nums){
pq.push(x);
while(pq.size()>k)pq.pop();
}
return pq.top();
}
};
class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
unordered_map<string,int>cnt;
unordered_set<string>vis;
for(auto x:words){
cnt[x]++;
vis.insert(x);
}
auto cmp=[&](auto a,auto b){
if(cnt[a]!=cnt[b])return cnt[a]>cnt[b];
return a<b;
};
priority_queue<string,vector<string>,decltype(cmp)>pq(cmp);
for(auto x:vis){
pq.push(x);
while(pq.size()>k)pq.pop();
}
vector<string>ans;
while(pq.size()){
ans.push_back(pq.top());
pq.pop();
}
reverse(ans.begin(),ans.end());
return ans;
}
};
I am the bone of my sword

浙公网安备 33010602011771号