数据结构与算法之最小优先队列

先简单介绍一下堆的结构特性。

堆的结构基于数组,堆中的元素都存储在数组中,存储元素的数组满足一下特性:

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的伙伴们共勉,每天记录一点点,每天进步一点点。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值