关于优先队列的数据结构:
优先队列的底层实现是堆;
下面介绍一下堆数据结构:堆数据结构是由数组构建的,最大堆:所有非叶子节点值都大于等于其左右孩子结点的值;
最小堆:所有非叶子节点值都小于等于左右孩子结点的值;
如何构建一个堆;伪代码如下(为了方便起见,数组的第一个元素的索引是1开始的)
1.首先得到相应的左结点和右结点的下标索引
PARENT(i)
return i / 2
LEFT(i)
return 2 * i
RIGHT(i)
2 * i + 1
2.从第一个非叶子节点开始,构建堆;(注意是从第一个非叶子节点开始构建堆)
A.heap-size = A.length
for A.length / 2 downto 1
MAX-HEAPIFY(A, i)
3.一下是递归的max_heapify(array,n)的伪代码:(非叶子节点和左右两个节点进行比较,选择大的数的索引,然后将大的数与起先的非叶子节点进行交换),交换后如果index!=largest_index ,还需要在交换后的结点进行维护
l = LIFT(i)
r = RIGHT(i)
if l <= A.heapsize and A[l] > A[i]
largest = l
else largest = i
if r <= A.heapsize and A[r] > A[largest]
largest = r
if largest != i
exchage A[i] with A[largest]
MAX-HEAPIFY(A, largest)
4,然后是堆排序算法:
伪代码是:交换相应的堆顶元素和数组尾部的元素,然后弹出数组最后一个元素,然后继续维护堆,max_heapify(array,n-1);
优先队列就是堆排序的一种应用;在c++中优先队列数据结构的使用,以及leetcode刷题如下:
leetcode347:
返回数组中前k个频率最大的数;
1.首先将数组进行遍历,然后通过map数据结构(hash)存储,然后对map中值进行排序,然后选择前k个数,时间复杂度为O(nlogn)主要的时间复杂度都是在排序算法上面;
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
//算法一实现:使用map数据结构来实现
unordered_map<int,int> nums_map;
for(int i=0;i<nums.size();i++){
nums_map[nums[i]]++;//同时也可以还是通过insert函数添加pair类型的数据;
}
unordered_map<int,int>::iterator iter=nums_map.begin();
vector<pair<int,int>> temp_nums;
for(iter;iter!=nums_map.end();iter++){
temp_nums.push_back(make_pair(iter->first,iter->second));
}
sort(temp_nums.begin(),temp_nums.end(),compare);
vector<int> ans;
//没有iter+i的用法,关联容器
for(int i=0;i<k;i++){
ans.push_back(temp_nums[i].first);
}
return ans;
}
static int compare(const pair<int,int>& pair1,const pair<int,int> &pair2){
if(pair1.second<pair2.second){
return false;
}
else{
return true;
}
}
};
时间复杂度为O(nlog(n));
2.使用优先队列来维护一个最小堆来实现相应;
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> nums_map;
for(int i=0;i<nums.size();i++){
nums_map[nums[i]]++;//同时也可以还是通过insert函数添加pair类型的数据;
}
//如何创建一个优先对垒priority_queue<int,vector<int>,greater<int>> 基本数据结构是int时,如果基本数据结构是pair<int,int>
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> min_queue;//构建了一个最小堆;
unordered_map<int,int>::iterator iter=nums_map.begin();
for(iter;iter!=nums_map.end();iter++){//对排序默认按照是键值进行排序
if(min_queue.size()==k){//如果已经维护了一个k个数字的最小堆
pair<int,int> temp=max_queue.top();//得到最大堆顶元素;
if(iter->second>temp.first){
min_queue.pop();//弹出最后的元素,k个值中的较小频率值
min_queue.push(pair<int,int>(iter->second,iter->first));
}
}
else{
min_queue.push(pair<int,int>(iter->second,iter->first));
}
}
vector<int> ans;
while(!min_queue.empty()){
ans.push_back(min_queue.top().second);
min_queue.pop();
}
return ans;
}
};
python 中也有相应的高级数据结构
from collections import defaultdict
import heapq
class Solution:
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
mydict=defaultdict(int)
for num in nums:
mydict[num]+=1
mylist=mydict.items()
ans_list=heapq.nlargest(k,mylist,key=lambda x:x[1])
result=[]
for item in ans_list:
result.append(item[0])
return result