先简单介绍一下堆的结构特性。
堆的结构基于数组,堆中的元素都存储在数组中,存储元素的数组满足一下特性:
1、最大的元素放在数组的1索引处
2、每个结点的元素的值总是大于等于它的两个子结点处的元素值
下面图可便于我们理解堆的结构
?这样实现的堆我们可以叫它最大堆,同样我们可以基于其反向思想实现最小堆,最小堆中数组元素须满足以下特性:
1、最小的元素放在数组的1索引处
2、每个结点的元素的值总是小于等于它的两个子结点处的元素值
图示如下
?最小优先队列API设计
?最小优先队列代码实现
/**
* @author: xuzhilei6656
* @create: 2021-12-12 17:21
* @description: 最小优先队列实现
**/
public class MinPriorityQueue<T extends Comparable<T>> {
//存储堆中元素
private final T[] items;
//记录元素个数
private int number;
//构造方法
public MinPriorityQueue(int capacity) {
this.items = (T[]) new Comparable[capacity+1];
this.number = 0;
}
//获取队列中元素个数
public int size(){
return number;
}
//判断队列是否为空
public boolean isEmpty(){
return number==0;
}
//判断堆中i索引处元素是否小于j索引处元素
public boolean less(int i,int j){
return items[i].compareTo(items[j]) < 0;
}
//交换i索引和j索引处的元素
public void exchange(int i,int j){
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}
//往堆中插入一个元素
public void insert(T t){
//在数组尾部追加
items[++number] = t;
//上浮调整
floatUp(number);
}
//对堆中k索引处元素做上浮调整,使索引k处元素处于合适的位置
private void floatUp(int k) {
while (k > 1){
//如果索引k处元素小于父结点索引k/2处元素,则交换两者的值
if (less(k,k/2)){
exchange(k,k/2);
}
//变换k
k = k/2;
}
}
//删除堆中最小的元素,并返回这个最小元素
public T delMin(){
//堆中第一个元素即为最小的元素
T min = items[1];
//交换1索引与最大索引处的元素值,让完全二叉树最后一个元素变为临时根结点
exchange(1,number);
//删除最大索引处的元素
items[number] = null;
//元素个数-1
number--;
//对1索引处元素进行下沉,让临时根结点处于合适的位置
sink(1);
return min;
}
//使用下沉算法,使索引k处元素在堆中处于一个正确的位置
private void sink(int k) {
while (2*k <= number){
//记录当前结点的左右子结点中较小者的索引
int min;
//如果存在右子结点,则左右子结点进行比较,否则让min直接记录左子结点元素所在索引
if (2*k+1 <= number){
//如果右子结点较小则min记录右子结点元素所在的索引,否则记录左子结点元素所在的索引
if (less(2*k+1,2*k)){
min = 2*k+1;
}else {
min = 2*k;
}
}else {
min = 2*k;
}
//如果索引k处元素小于min处索引的元素,则说明索引k处元素处于正确的位置,结束循环,停止下沉
if (less(k,min)){
break;
}
//交换索引k和索引min处的元素
exchange(k,min);
//变换k
k = min;
}
}
//测试
public static void main(String[] args) {
String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "B"};
MinPriorityQueue<String> queue = new MinPriorityQueue<>(20);
for (String str : arr){
queue.insert(str);
}
System.out.println(queue.size());
while (!queue.isEmpty()){
String min = queue.delMin();
System.out.println(min);
}
}
}
?测试结果
?以上仅个人学习时随手敲的demo,如有不正确的地方,可以在下方留言指正,谢谢。与各位CSDN的伙伴们共勉,每天记录一点点,每天进步一点点。
|