【数据结构与算法】第九章:优先队列(最大、最小、索引)

普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,可能需要找出队列中的最大值或者最小值

例如:使用一个队列保存计算机的任务,一般情况下计算机的任务都是有优先级的,需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,就可以使用一种特殊的队列来完成这种需求,优先队列

在这里插入图片描述

优先队列按照其作用不同,可以分为以下两种:

  • 最大优先队列: 可以获取并删除队列中最大的值

  • 最小优先队列: 可以获取并删除队列中最小的值

9.1、最大优先队列

这种结构是可以方便的删除最大的值,所以,可以基于堆实现最大优先队列

最大堆

1)API设计

在这里插入图片描述

2)代码实现

package chapter07;

/**
 * @author 土味儿
 * Date 2021/9/9
 * @version 1.0
 * 最大优先队列
 * 以堆的方式实现
 */
public class MaxPriorityQueue<T extends Comparable<T>> {
   
    /**
     * 存储元素的数组
     */
    private T[] items;
    /**
     * 元素个数
     */
    private int n;

    /**
     * 构造器
     *
     * @param capacity
     */
    public MaxPriorityQueue(int capacity) {
   
        this.items = (T[]) new Comparable[capacity + 1];
        this.n = 0;
    }

    /**
     * 元素个数
     *
     * @return
     */
    public int size() {
   
        return n;
    }

    /**
     * 是否为空
     *
     * @return
     */
    public boolean isEmpty() {
   
        return n < 1;
    }

    /**
     * 插入元素
     *
     * @param t
     */
    public void insert(T t) {
   
        // 在结尾插入
        items[++n] = t;
        // 让新元素上浮,找到合适的位置
        swim(n);
    }

    /**
     * 删除最大元素并返回
     *
     * @return
     */
    public T delMax() {
   
        // 最大元素
        T max = items[1];

        // 交换索引1处 和 最大索引处的元素,让完全二叉树中最右的元素成为临时根结点
        exch(1, n);

        // 删除交换后最大索引处的元素,即原根结点(最大元素)
        items[n] = null;

        // 元素数量减1
        n--;

        // 让新根结点下沉,找到合适位置
        sink(1);

        return max;
    }

    /**
     * 比较索引i处元素是否小于j处元素
     *
     * @param i
     * @param j
     * @return
     */
    private boolean less(int i, int j) {
   
        return items[i].compareTo(items[j]) < 0;
    }

    /**
     * 交换索引i处和j处元素
     *
     * @param i
     * @param j
     */
    private void exch(int i, int j) {
   
        T temp = items[i];
        items[i] = items[j];
        items[j] = temp;
    }

    /**
     * 让索引k处元素上浮到合适的位置
     *
     * @param k
     */
    private void swim(int k) {
   
        // 循环比较索引k处元素和它父结点元素,如果父结点小,就交换位置
        while (k > 1) {
   
            // 比较当前结点与父结点
            if (less(k / 2, k)) {
   
                // 父比子小,交换位置
                exch(k / 2, k);
            }
            k = k / 2;
        }
    }

    /**
     * 让索引k处元素下沉到合适的位置
     *
     * @param k
     */
    private void sink(int k) {
   
        // 循环比较当前结点k 和 max(左子结点2k,右子结点2k+1)的值,如果当前结点k小,就交换位置

        // 循环条件 2*k <= n :表示存在 左子结点
        while (2 * k <= n) {
   
            // 获取当前结点中的较大 子结点

            // 记录较大 子结点索引:默认为 左子结点
            int max = 2 * k;
            // 如果右结点存在,且左小于右,改变max
            if (2 * k + 1 <= n && less(2 * k, 2 * k + 1)) {
   
                max = 2 * k + 1;
            }

            if (!less(k, max)) {
   
                // 当前结点不小于子结点,退出循环
                break;
            }

            // 当前结点小于子结点,交换位置
            exch(k, max);

            // 交换k值,继续循环
            k = max;
        }
    }
}
    @Test
    public void testMaxPriorityQueue() {
   
        String[] arr = {
   "E", "B", "A", "C", "D"};
        MaxPriorityQueue<String> maxpq = new MaxPriorityQueue<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土味儿~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值