前言
堆,优先级队列,底层为一维数组,逻辑上是一个完全二叉树。
以下均以小顶堆为例:父节点为 p,两个子节点为 l 和 r 。下标转换关系:(画出即可得到该转换关系)
l = 2 * p + 1 ,r = l + 1;
p = ( l - 1 ) / 2 或者 p = ( r - 1 ) / 2;
堆中重要的两个方法:push() 和 pop()
push() :向堆中添加一个新元素,新元素添加至数组末尾,然后呢,向上调整堆,调整采用的方法为交换。
pop() :获取堆顶元素,然后将堆顶元素的值置为末尾元素值,删除末尾元素,然后向下调整堆。
具体的 Java 实现如下,可供参考:
代码实现
import java.util.*;
public class MyPriortyQueue {
private List<Integer> arr;
MyPriortyQueue(){
arr=new ArrayList<>();
}
public boolean isEmpty(){
return arr.size()==0;
}
public void push(int val){
arr.add(val);
adjustUp();
}
private void adjustUp(){
int cur=arr.size()-1;
int p=(cur-1)/2;
while(p>=0){
if(arr.get(p)>arr.get(cur)){
Collections.swap(arr,p,cur);
cur=p;
p=(cur-1)/2;
}
else
break;
}
}
public int pop(){
if(isEmpty())
return -1;
int tmp=arr.get(0);
adjustDown();
return tmp;
}
private void adjustDown(){
Collections.swap(arr,0,arr.size()-1);
arr.remove(arr.size()-1);
int cur=0,l=2*cur+1,r=l+1;
while(l<arr.size()){
if(r>=arr.size()){
if(arr.get(cur)>arr.get(l))
Collections.swap(arr,cur,l);
break; // 堆为一个完全二叉树,此时直接 break;
}
int min=arr.get(l)<arr.get(r)?l:r;
if(arr.get(cur)>arr.get(min)){ //只需要和最小的比较即可
Collections.swap(arr,cur,min);
cur=min;
l=2*cur+1;
r=l+1;
}
else
break;
}
}
public int size(){
return arr.size();
}
public static void main(String[] args) {
MyPriortyQueue p=new MyPriortyQueue();
p.push(4);
p.push(9);
p.push(3);
p.push(7);
p.push(2);
while(!p.isEmpty())
System.out.print(p.pop()+" ");
System.out.println();
PriorityQueue<Integer> pp=new PriorityQueue<>();
pp.add(4);
pp.add(9);
pp.add(3);
pp.add(7);
pp.add(2);
while(!pp.isEmpty())
System.out.print(pp.poll()+" ");
}
}
总结
大顶堆的实现参照小顶堆即可。