算法思想
堆的概念
堆:通常可以看成是一个完全二叉树的数组。(堆排序实际上是堆中元素的交换,因此可以用数组实现,并且数组的查询和修改效率比较高,能够提高性能)
堆的两种形式:
- 大顶堆:根节点大于左右孩子的节点
- 小顶堆:根节点小于左右孩子的节点
构造堆
1、二叉树堆结构中元素与数组堆结构中元素的对应关系:(大小顶堆一样的)
那么对于某一个节点 index,它的左右孩子在数组中的下标分别为:
- Left=index*2+1
- Right=index*2+2
叶子结点和非叶子节点的区别:
- 非叶子节点的下标<节点个数/2-1
- 叶子节点的下标>节点个数/2-1
2、大顶堆的维护(核心)
自下而上地维护一个大顶堆,使其满足大顶堆的性质:非叶子节点的左右孩子都小于它的根节点
维护分为初始化时大顶堆的维护和初始化后大顶堆的维护:
- 刚开始将待排序数组中的前k个元素复制到堆结构中的数组中,并调用HeapAdjust()方法,从非叶子节点开始,自下而上地维护;
- 而对于新插入的剩下的n-k个元素,只有当元素小于大顶堆的根节点时,才会移除根节点,并将该元素加入大顶堆。因此除了0号元素可能不满足大顶堆的性质外,它的下层的非叶子节点都满足性质,所以**维护的实质是:**维护index=0的情况。
优先队列实现堆排序
优先级队列的元素按照自然排序进行排序,或者根据构造队列时提供的 **Comparator(比较器)**进行排序,具体取决于所使用的构造方法。优先级队列不允许使用 null 元素,依靠自然排序的优先级队列还不允许插入不可比较的对象(这样容易导致 ClassCastException)。
队列的头相当于堆的根节点
构造方法:
a.无 Comparator 参数:默认自然排序,实现小顶堆;
b.传入 Comparator:重写里面的 compare 方法,实现大顶堆。(常用)
PriorityQueue(int initialCapacity)
//使用指定的初始容量创建一个PriorityQueue,并根据自然排序对元素排序
PriorityQueue(int initialCapacity,Comparator<? super E> comparator)
//使用指定的初始容量创建一个PriorityQueue,并根据指定的比较器对元素排序
范例:(第二个构造方法)
PriorityQueue<Integer> pq=new PriorityQueue<>(k,new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o2-o1;
}
});
/*
返回0:o1等于o2,是同一元素
返回正数:认为o2大于o1,让o2排在更靠近队列头部的位置
返回负数:认为o2小于o1,让o2排在远离队列头部的位置
这样就构成了大顶堆,相反当返回的是o1-o2时,比如返回正数,仍然认为o2大于o1,让小数o2排在了更靠近队列头部的位置
*/
相关题目
题目一
输出数组中出现频率前K高的元素
解题思路
借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
通过比较器指定排序规则,即频率越高的元素越靠近队列的头部,排序过程如下图所示:
代码及注解
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> requence=new HashMap<>();
for(int num:nums){
if(requence.containsKey(num)){
requence.put(num,requence.get(num)+1);
}else{
requence.put(num,0);
}
}
PriorityQueue<Integer> pq=new PriorityQueue<>(k,new Comparator<Integer>(){
@Override
public int compare(Integer num1,Integer num2){
return requence.get(num1)-requence.get(num2);
}
});
for(int num:requence.keySet()){
if(pq.size()<k){//当队列中元素个数小于k时,向队列中添加元素,先将队列中元素增加到k个
pq.offer(num);
}else if(requence.get(num)>requence.get(pq.peek())){//当队列中头部元素大于HashMap中频率时,先将头部弹出,再向队列中添加出现频率更高的元素
pq.poll();
pq.offer(num);
}
}
int[] res=new int[k];
int i=0;
while(!pq.isEmpty()){
res[i]=pq.poll();
i++;
}
return res;
}
}