版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LoveHYZH/article/details/79120744
1.什么是优先队列
- 支持插入和删除最小值操作,或者插入和删除最大值操作,等价于队列的入队和出队操作
- 根据优先级高低而不是先到先服务的方式来进行调度
- 如果最小键值元素拥有最高优先级,那么这种优先队列叫做升序优先队列
- 如果最大键值元素拥有最高优先级,那么这种优先队列叫做降序优先队列
- 一般用堆实现
2.优先队列ADT
- 优先队列的主要操作
优先队列是元素的容器,每个元素有一个相关键值
insert(key, data):插入键值为key的数据到优先队列,元素以其key进行排序
deleteMin()/deleteMax():删除并返回最值元素
getMinimum()/getMaximum():返回最值元素,但不删除 - 优先队列的辅助操作
查找第k 大/小的元素
返回优先队列的大小(元素个数)
堆排序(Heap Sort)
3.堆(二叉堆已经足够满足需求)
- 什么是堆
堆是一棵具有特定性质的二叉树
堆的基本要求是堆中所有节点的值必须大于等于(或者小于等于)其孩子节点的值
堆应该是一棵完全二叉树 - 堆的表示
由于堆在形式上是一棵完全二叉树,所以用数组不会浪费存储空间
4.堆的实现
public class Heap {
public static enum HeapType{
MaxHeap,
MinType;
}
private int[] ary;
private int size; //堆中元素个数
private int capacity; //堆的大小
private HeapType heapType; //堆的类型
/**
* 创建堆
* @param heapType 堆的类型
* @param capacity 堆的大小
*/
public Heap(HeapType heapType){
this.heapType = heapType;
this.capacity = 10;
this.size = 0;
this.ary = new int[capacity];
}
/**
* @param i 元素在数组中的下标
* @return 父元素在数组中的下标, 返回-1表示不存在双亲
*/
private int parentIndex(int i){
if(i <= 0 || i >= this.size){
return -1; //不存在双亲节点
}
return (i - 1) / 2;
}
/**
* @param i 元素在数组中的下标
* @return 左孩子在数组中的下标, 返回-1表示不存在左孩子
*/
private int lchildIndex(int i){
int left = 2 * i + 1;
if(left > size){
return -1;
}
return left;
}
/**
* @param i 元素在数组中的下标
* @return 右孩子在数组中的下标, 返回-1表示不存在右孩子
*/
private int rchildIndex(int i){
int right = 2 * i + 2;
if(right > size){
return -1;
}
return right;
}
/**
* @return 获得堆顶元素
*/
public int top(){
if(size <= 0){
throw new NoSuchElementException("堆为空");
}
return ary[0];
}
/**
* 最大堆堆化(下渗)
* @param i 节点下标
*/
private void maxHeapPercolateDown(int i){
int l, r, max;
int temp;
l = lchildIndex(i);
r = rchildIndex(i);
if(l != -1 && ary[l] > ary[i]){
max = l;
}else{
max = i;
}
if(r != -1 && ary[r] > ary[max]){
max = r;
}
if(i != max){
temp = ary[i];
ary[i] = ary[max];
ary[max] = temp;
maxHeapPercolateDown(max);
}
}
/**
* 最小堆堆化(下渗)
* @param i 节点下标
*/
private void minHeapPercolateDown(int i){
int l, r, min;
int temp;
l = lchildIndex(i);
r = rchildIndex(i);
if(l != -1 && ary[l] < ary[i]){
min = l;
}else{
min = i;
}
if(r != -1 && ary[r] < ary[min]){
min = r;
}
if(i != min){
temp = ary[i];
ary[i] = ary[min];
ary[min] = temp;
minHeapPercolateDown(min);
}
}
/**
* @return 删除并返回堆顶元素
*/
public int remove(){
if(size == 0){
throw new RuntimeException("堆为空,不允许删除元素");
}
int temp = ary[0];
ary[0] = ary[size--];
switch(heapType){
case MaxHeap:
maxHeapPercolateDown(0);
break;
default:
minHeapPercolateDown(0);
}
return temp;
}
/**
* @param i 最大堆指定元素上浮
*/
private void maxHeapPercolateUp(int i){
int temp;
int p =parentIndex(i);
if(p != -1 && ary[i] > ary[p]){
temp = ary[i];
ary[i] = ary[p];
ary[p] = temp;
maxHeapPercolateUp(p);
}
}
/**
* @param i 最小堆指定元素上浮
*/
private void minHeapPercolateUp(int i){
int temp;
int p =parentIndex(i);
if(p != -1 && ary[i] < ary[p]){
temp = ary[i];
ary[i] = ary[p];
ary[p] = temp;
minHeapPercolateUp(p);
}
}
//扩容
private void resizeHeap(int newCapacity){
int[] old_ary = ary;
capacity *= 2;
if(capacity < newCapacity){
capacity = newCapacity;
}
this.ary = new int[capacity];
System.arraycopy(old_ary, 0, ary, 0, size);
}
/**
* 插入元素
* @param data
*/
public void add(int data){
if(size == capacity){
resizeHeap(size + 1);
}
++size;
ary[size - 1] = data;
switch(heapType){
case MaxHeap:
maxHeapPercolateUp(size - 1);
break;
default:
minHeapPercolateUp(size - 1);
}
}
/**
* 插入数组
* @param data
*/
public void add(int[] data){
int n = data.length;
if(size == capacity){
resizeHeap(size + n);
}
for(int i = 0; i < n; i++){
++size;
ary[size - 1] = data[i];
}
switch(heapType){
case MaxHeap:
for(int i = parentIndex(size - 1); i >= 0; i--){
maxHeapPercolateDown(i);
}
break;
default:
for(int i = parentIndex(size - 1); i >= 0; i--){
minHeapPercolateDown(i);
}
}
}
/**
* 清空堆
*/
public void clear(){
size = 0;
ary = null;
}
}