优先队列

优先队列概述

普通的队列是一种先进先出(FIFO)的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值,例如使用一个队列保存计算机的任务,一般情况下计算机的任务都是有优先级的,我们需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,我们就可以使用一种特殊的队列来完成这种需求,优先队列。
在这里插入图片描述
优先队列按照其作用不同,可以分为以下两种:
 最大优先队列:

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

最大优先队列

我们之前学习过堆,而堆这种结构是可以方便的删除最大的值,所以,接下来我们可以基于堆区实现最大优先队列。(优先队列底层是基于堆实现的。)
最大优先队列API设计
在这里插入图片描述
创建API

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;
    }
    //获取队列中元素的个数
    public int size(){
        return N;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return N==0;
    }
    //判断堆中索引i处的元素是否小于索引j处的元素
    private boolean less(int i,int j){
        return items[i].compareTo(items[j])<0;
    }
    //交换堆中i和j索引处的值
    private void exch(int i,int j){
        T tmp = items[i];
        items[i] = items[j];
        items[j] = tmp;
    }
    //往堆中插入一个元素
    public void insert(T t){
        items[++N] = t;
        swim(N);
    }
    //删除堆中最大的元素,并返回这个值
    /**
     * 删除并获取堆顶元素
     * 1)获取堆顶元素
     * 2)将堆中最后一个元素移动到堆顶
     * 3)删除堆中最后一个元素
     * 4)利用下沉算法,让最后一个元素回到正确的位置
     * 5)堆再次有序
     * @return
     */
    public T delMax(){
        T max = items[1];
        exch(1,N);
        N--;
        sink(1);
        return max;
    }
    //使用上浮算法,使索引K处的元素能在堆中处于一个正确的位置
    /**
     * 对插入元素导致堆无序,进行上浮操作
     * 1)每次与k的父节点相比,如果小于其父节点,则需要交换位置
     * @param k 造成无序的元素
     */
    private void swim(int k){
        while (k > 1){
            if(less(k/2,k)){
                exch(k/2,k);
            }
            k /= 2;
        }
    }
    //使用下沉算法,使索引K处的元素能在堆中处于一个正确的位置
    /**
     * 对删除堆顶元素后导致堆无序,需要进行下沉操作,保证顺序
     * 1)找到k的左右子树
     * 2)找出k左右子树的最大值
     * 3)比较其与k的大小
     * 4)如果大于k,则交换位置   (下沉)
     * 5)如果不大于k,则无需操作
     * @param k
     */
    public void sink(int k){
        int max = 0;
        //判断k位置的元素具有左右子树
        while (2*k<=N){
            max = 2*k;
            //判断是否有右子结点
            if(2*k+1<=N){
                if (less(2*k,2*k+1)){
                    max = 2*k+1;
                }
            }
            //判断当前结点与其子结点中的最大值大小
            if (less(k,max)){
                exch(k,max);
            }else{
                break;
            }
            //将k移动到其最大子树上,继续向下判断
            k = max;
        }
    }

}

创建主方法测试

public class MPQT {
    public static void main(String[] args) {
        MaxPriorityQueue<String> queue = new MaxPriorityQueue<>(10);
        queue.insert("A");
        queue.insert("B");
        queue.insert("C");
        queue.insert("D");
        queue.insert("E");
        queue.insert("F");
        queue.insert("G");
        while (!queue.isEmpty()){
            String max = queue.delMax();
            System.out.print(max + " ");
        }
    }
}

最小优先队列

基于上面最大优先队列的思路,我们可以得到最小优先队列的代码如下所示。

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;
    }
    //获取队列中元素的个数
    public int size(){
        return N;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return N==0;
    }
    //判断堆中索引i处的元素是否小于索引j处的元素
    private boolean less(int i,int j){
        return items[i].compareTo(items[j])<0;
    }
    //交换堆中i和j索引处的值
    private void exch(int i,int j){
        T tmp = items[i];
        items[i] = items[j];
        items[j] = tmp;
    }
    //往堆中插入一个元素
    public void insert(T t){
        items[++N] = t;
        swim(N);
    }
    //删除堆中最大的元素,并返回这个值
    public T delMax(){
        T min = items[1];
        exch(1,N);
        items[N] = null;
        N--;
        sink(1);
        return min;
    }
    //使用上浮算法,使索引K处的元素能在堆中处于一个正确的位置
    private void swim(int k){
        while (k > 1){
            if(less(k,k/2)){
                exch(k,k/2);
            }else {
                break;
            }
            k /= 2;
        }
    }
    //使用下沉算法,使索引K处的元素能在堆中处于一个正确的位置
    public void sink(int k){
        int min = 0;
        //判断k位置的元素具有左右子树
        while (2*k<=N){
            min = 2*k;
          
            if(2*k+1<=N){
                if (less(2*k,2*k+1)){
                    min = 2*k+1;
                }
            }
           
            if (less(min,k)){
                exch(min,k);
            }else{
                break;
            }
         
            k = min ;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值