最大优先队列
实际上就使基于最大堆实现的,取出元素时取出堆中最大的元素即可,并非先进先出
public class MaxPriorityQueue<T extends Comparable<T>> {
//存储元素的数组
private T[] items;
//记录堆中元素的个数
private int N;
//优先队列构造方法
public MaxPriorityQueue(int capacity){
this.items= (T[]) new Comparable[capacity+1];
this.N=0;
}
/**
* 返回优先队列中存储的元素个数
* @return
*/
public int size(){return N;}
/**
* 优先队列是否为空
* @return true 空 false 不为空
*/
public boolean isEmpty(){return N==0;}
/**
* i索引处的值是否小于j索引处的值
* @param i
* @param j
* @return true 小于 false 大于
*/
private boolean less(int i,int j){
return items[i].compareTo(items[j])<0;
}
/**
* 交换索引i与索引j处的元素
* @param i
* @param j
*/
private void exchange(int i,int j){
T temp=items[i];
items[i]=items[j];
items[j]=temp;
}
/**
* 往堆中插入一个元素
* @param t
*/
public void insert(T t){
if (isEmpty()){
//队列中无存储元素,新增元素为根结点元素
items[1]=t;
//元素个数+1
N++;
return;
}
//队列中已存储元素,将新元素存储到数组的最后一个元素的后一位
items[N+1]=t;
//元素个数+1
N++;
//利用上浮算法将新增的元素置于堆结构的正确位置
swim(N);
}
/**
* 上浮算法,将所有k处的元素调整到堆中正确的位置,保持堆的结构
* @param k
*/
private void swim(int k){
while (k/2>=1){
//当前结点有父结点,与父结点比较大小
if (less(k,k/2)){
//当前结点小于父结点的值,那么该位置就为正确位置直接结束循环
break;
}
//当前结点的值大于父结点的值,则交换二者元素
exchange(k,k/2);
//交换元素后继续循环比较与新结点位置父结点的值大小
k=k/2;
}
}
/**
* 删除最大优先队列中的最大元素(即堆中根结点的元素)并返回
* @return
*/
public T delMax(){
//交换索引1与索引N处的元素
exchange(1,N);
//创建临时根结点
T temp=items[N];
//删除最后最大元素
items[N]=null;
//元素个数-1
N--;
//让临时根结点的元素下沉到正确位置
sink(1);
//返回最大元素
return temp;
}
/**
* 下沉算法,使索引k位置的元素下沉到正确的位置
* @param k
*/
private void sink(int k){
if (isEmpty()){
//堆为空 无需下沉
return;
}
//堆不为空
while (2*k<=N){
//当前结点存在左子结点
int max;//记录左右子结点中较大者的索引
if(2*k+1<=N){
//存在右子结点
if(less(2*k,2*k+1)){
//左子结点的元素小于右子结点的元素
max=2*k+1;
}else {
//左子结点的元素大于右子结点的元素
max=2*k;
}
}else {
//右子结点不存在
max=2*k;
}
//比较当前结点与max索引的大小
if(!less(k,max)){
//当前结点比max索引的值大,正确该元素已经下沉到正确的位置,直接结束循环
break;
}
//当前结点比max索引的值小,交换元素继续下沉寻找正确位置
exchange(k,max);
k=max;
}
//循环结束条件
// 1.无左子结点,已经沉到低(该位置为正确位置)
//2.找到了正确位置提前结束了循环
}
}
最小优先队列
实际上是基于最小堆实现的,取出元素时取出堆中最小的元素即可
public class MinPriorityQueue<T extends Comparable<T>> {
//存储元素的数组
private T[] items;
//记录堆中元素的个数
private int N;
//优先队列构造方法
public MinPriorityQueue(int capacity){
this.items= (T[]) new Comparable[capacity+1];
this.N=0;
}
/**
* 返回优先队列中存储的元素个数
* @return
*/
public int size(){return N;}
/**
* 优先队列是否为空
* @return true 空 false 不为空
*/
public boolean isEmpty(){return N==0;}
/**
* i索引处的值是否小于j索引处的值
* @param i
* @param j
* @return true 小于 false 大于
*/
private boolean less(int i,int j){
return items[i].compareTo(items[j])<0;
}
/**
* 交换索引i与索引j处的元素
* @param i
* @param j
*/
private void exchange(int i,int j){
T temp=items[i];
items[i]=items[j];
items[j]=temp;
}
/**
* 往堆中插入一个元素
* @param t
*/
public void insert(T t){
if (isEmpty()){
//队列中无存储元素,新增元素为根结点元素
items[1]=t;
//元素个数+1
N++;
return;
}
//队列中已存储元素,将新元素存储到数组的最后一个元素的后一位
items[N+1]=t;
//元素个数+1
N++;
//利用上浮算法将新增的元素置于堆结构的正确位置
swim(N);
}
/**
* 上浮算法,将所有k处的元素调整到堆中正确的位置,保持堆的结构
* @param k
*/
private void swim(int k){
while (k/2>=1){
//当前结点右父结点
if(!less(k,k/2)){
//当前结点大于父结点,则已经上浮到了正确位置直接结束循环
break;
}
//当前结点小于父结点,交换元素 继续上浮
exchange(k,k/2);
k=k/2;
}
}
/**
* 删除最小优先队列中的最小元素(即堆中根结点的元素)并返回
* @return
*/
public T delMin(){
//交换索引1与索引N处的元素
exchange(1,N);
//创建临时根结点
T temp=items[N];
//删除最后最小元素
items[N]=null;
//元素个数-1
N--;
//让临时根结点的元素下沉到正确位置
sink(1);
//返回最大元素
return temp;
}
/**
* 下沉算法,使索引k位置的元素下沉到正确的位置
* @param k
*/
private void sink(int k){
if (isEmpty()){
//堆为空 无需下沉
return;
}
//堆不为空
while (2*k<=N){
//当前结点存在左子结点进行下沉
int min;//记录当前子结点的左右子结点中值较小的索引
if (2*k+1<=N){
//当前子结点存在左右子结点
if (less(2*k,2*k+1)){
//左子结点的值小于右子结点的值
min=2*k;
}else {
//左子结点的值大于右子结点的值
min=2*k+1;
}
}else {
//右子结点不存在
min=2*k;
}
//比较当前结点与min
if (less(k,min)){
//当前结点小于min。已经下沉到了正确的位置 停止循环
break;
}
//当前结点大于min 交换元素继续下沉寻找正确位置
exchange(k,min);
k=min;
}
//循环结束条件
// 1.无左子结点,已经沉到低(该位置为正确位置)
//2.找到了正确位置提前结束了循环
}
}