目录
一、堆的创建:
默认是以最小堆创建,如果要创建大根堆,那么使用如下:
java
//创建大根堆
PriorityQueue<Integer> queue=new PriorityQueue<>(Collections.reverseOrder());
//Collections.reverseOrder()类似于反转
//默认小根堆创建
PriorityQueue<Integer> queue=new PriorityQueue<>();
二、堆的插入(以大根堆进行调整):
思路:
1.先判满,满的话就扩容,用Arrays.Copy(elem,2*elem.length)扩容。
2.向上调整
3.定义parent变量,是最后一个子树的父节点,child是最后一个节点
4.进行比较,如果elem[parent]<elem[child]就交换,循环前提是parent>=0;
java
public void push(int val) {
if(isFull()){
elem=Arrays.copyOf(elem,2*elem.length);
}else{
elem[usedSize]=val;
usedSize++;
shiftUp(usedSize-1);
}
}
//判满
public boolean isFull() {
return this.usedSize==elem.length;
}
//向上调整
private void shiftUp(int child) {
int parent=(child-1)/2;
while(parent>=0){
if(elem[child]>elem[parent]){
int tmp=elem[child];
elem[child]=elem[parent];
elem[parent]=tmp;
child=parent;
parent=(child-1)/2;
}else{
break;
}
}
}
三、堆的删除(最大堆):
思路:
1.先判空,如果是空的就抛异常
2.把堆头元素和最后一个元素进行交换,然后usedsize--,这样就会减少一个元素然后向下调整
3.循环判断child<len
4.进入循环之后,还要判断右子树是否存在,如果存在,那么说明child+1<len
5.如果elem[parent]<elem[child]就交换
java
/**
* 出队【删除】:每次删除的都是优先级高的元素
* 仍然要保持是大根堆
*/
public void pollHeap() {
if(isEmpty()){
throw new RuntimeException();
}
int tmp=elem[0];
elem[0]=elem[usedSize-1];
elem[usedSize-1]=tmp;
usedSize--;
shiftDown(0,usedSize);
}
/**
*
* @param root 是每棵子树的根节点的下标
* @param len 是每棵子树调整结束的结束条件
* 向下调整的时间复杂度:O(logn)
*/
private void shiftDown(int root,int len) {
int child=2*root+1;
while(child<len){
if(child+1<len&&elem[child]<elem[child+1]){
child++;
}
if(elem[root]<elem[child]){
int tmp=elem[root];
elem[root]=elem[child];
elem[child]=tmp;
root=child;
child=2*root+1;
}else{
break;
}
}
}
public boolean isEmpty() {
return usedSize==0;
}
四、top-k问题(最小的k个数):
思路:
1.先创建堆
2.把元素依次放入堆中
3.遍历前k个并打印
java
class Solution {
public int[] smallestK(int[] arr, int k) {
PriorityQueue<Integer> queue=new PriorityQueue<>(Collections.reverseOrder());
for(int i=0;i< arr.length;i++){
queue.offer(arr[i]);
}
int[] my_arr=new int[k];
for(int i=0;i<k;i++){
my_arr[i]=queue.poll();
}
return my_arr;
}
}
五、优化top-k问题:
思路:
1.如果是求前k个最小,那么就要创建大根堆,如果求前k个最大,那么就创建小根堆
2.创建大小为k的大根堆,把前k个元素放入堆中
3.从k下标开始遍历,先得到堆头元素,拿去跟当前下标k的数组的元素进行比较,如果堆头元素大于当前数组下标k的值,那么就要弹出堆头元素,把数组当前下标k的值入堆。直到遍历结束,这时候堆就会得到最小的k个数。
java
class Solution {
public int[] smallestK(int[] arr, int k) {
int[] tmp=new int[k];
if(k==0){
return tmp;
}
PriorityQueue<Integer> queue=new PriorityQueue<>(Collections.reverseOrder());
for(int i=0;i<k;i++){
queue.offer(arr[i]);
}
for(int i=k;i<arr.length;i++){
int val=queue.peek();
if(val>arr[i]){
queue.poll();
queue.offer(arr[i]);
}
}
for(int i=0;i<k;i++){
tmp[i]=queue.poll();
}
return tmp;
}
}