优先级队列

1.通过优先级比较出队列,比如,手机玩游戏时,如果有电话打进来,那么系统先处理打进来的电话
2.java集合框架提供了两种类型的优先级队列,分别是:priorityqueue(非线程安全)priorityblockingqueue(线程安全)
3.注意:

  • priorityqueue中放置的元素必须要能够进行比大小,不能插入无法比较大小的对象,否则抛异常(ClassCastException异常
  • 不能插入null对象,否则会抛空指针异常
  • 没有容量限制,可以插任意多个元素, 其内部可以自动扩容
  • 插入和删除元素的时间复杂度为O(log2^N)
  • 底层使用了这种数据结构

4.优先级队列的构造

1.PriorityQueue()
创建了空的优先级队列,默认容量是11
2. PriorityQueue(int 初始容量)
创建带有初始容量的优先级队列,初始容量不能小于11,否则抛异常
3.PriorityQueue(Collection<? extends E> c)
用一个集合来创建优先级队列

static void TestPriorityQueue(){
 // 创建一个空的优先级队列,底层默认容量是11
 PriorityQueue<Integer> q1 = new PriorityQueue<>();
 // 创建一个空的优先级队列,底层的容量为initialCapacity
 PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
 ArrayList<Integer> list = new ArrayList<>();
 list.add(4);
 list.add(3);
 list.add(2);
 list.add(1);
 // 用ArrayList对象来构造一个优先级队列的对象
 // q3中已经包含了三个元素
 PriorityQueue<Integer> q3 = new PriorityQueue<>(list);
 System.out.println(q3.size());
 System.out.println(q3.peek());
 }

在这里插入图片描述
4.优先级队列扩容的规则:

  • 如果容量小于64时,是按照oldCapacity*2 + 2的方式扩容的
  • 如果容量大于等于64,是按照oldCapacity*2的方式扩容的
  • 如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

实现:

package queue;

import java.util.Arrays;
interface Compare{
    public int compare(int left,int right);
}

class Less implements Compare{
    //0:left==right
    //>0:left>right
    //<0:left<right
    public int compare(int left, int right){
        return left-right;
    }
}

class Greater implements Compare{
    public int compare(int left, int right){
        return right-left;
    }
}
//实现小堆
public class MyPriorityQueue {
    private int[] array;//存放数据
    private int size = 0;//优先级队列中有效元素的个数
    private Compare compare=null;
    /*public MyPriorityQueue(Compare comp) {
        //默认的构造,将其底层默认容量设置为11
        array = new int[11];
        size = 0;
        compare=comp;
    }*/

    /*public MyPriorityQueue(int initCapacity,Compare comp) {
        if (initCapacity < 1) {
            //标准库:抛出非法参数的异常
            //这里设置为11
            initCapacity = 11;
        }
        array = new int[initCapacity];
        size = 0;
        compare=comp;
    }*/

    //标准库中没有该接口--标准库中可以采用集合来构造优先级队列
    public MyPriorityQueue(int[] arr,Compare comp) {
        array = new int[arr.length];
        /*for (int i = 0; i < arr.length; i++) {
            array[i] = arr[i];
        }*/
        System.arraycopy(arr,0,array,0,arr.length);
        size = array.length;
        //将array中的元素进行调整,满足堆的特性
        //找到倒数第一个非叶子节点
        compare=comp;

        int lastLeaf = (array.length - 2) >> 1;
        for (int root = lastLeaf; root >= 0; root--) {
            shiftDown(root);
        }
    }

    //获取堆顶元素
    public int peek() {
        //标准库中,如果优先级队列是空,无法返回堆顶元素,返回null
        return array[0];
    }

    //获取优先级队列有效元素个数
    private int size() {
        return size;
    }

    //清空
    private void clear() {
        size = 0;
    }

    //插入
    private void offer(int x) {
        //插入元素之前需要判断是否需要扩容
        grow();
        array[size++] = x;
        shiftUp(size - 1);//注意:此处一定不能使用size--
    }

    //删除最小元素,堆顶元素
    int poll() {
        int ret = array[0];
        swap(0, size - 1);
        size--;
        shiftDown(0);
        return ret;
    }

    //判空
    boolean isEmpty() {
        return size == 0;
    }

    //只是模拟优先级队列扩容的一部分
    private void grow() {
        if (size >= array.length) {
            int oldCapacity = array.length;
            //扩容方式:原容量<64的:原容量的二倍加二,否则:原容量的1.5倍进行扩容
            int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));
            array = Arrays.copyOf(array, newCapacity);//拷贝
        }
    }

    //调整的方法
    //调整以parent为根的二叉树,调整之前一定要保证左右子树已经满足小堆的性质
    //不满足就交换,交换后可能导致子树不满足堆的性质,继续调整子树
    public void shiftDown(int parent) {
        //如果要检测parent是否满足小堆的性质,只需要和孩子比较
        int child = parent * 2 + 1;//child标记较小的孩子,parent可能有左没有右孩子
        while (child < size) {
            //找parent左右孩子中较小的孩子
            // if(child + 1 < size && array[child + 1] < array[child]) {//保证右孩子存在,while循环条件已经保证左孩子存在
            if (child+1<size&&compare.compare(array[child+1],array[child])<0){
            child += 1;
            }
            //检测parent与较小孩子的大小
            //if (array[child] < array[parent]) {
            if (compare.compare(array[child],array[parent])<0){
                //不满足小堆性质
                swap(parent, child);
                //交换后可能破坏子树结构
                parent = child;
                child = parent * 2 + 1;
            } else {
                //满足
                return;
            }
        }
    }

    //向上调整
    public void shiftUp(int child) {
        int parent = (child - 1) >> 1;
        while (child != 0) {//或者parent
            //if (array[child] < array[parent]) {
            if (compare.compare(array[child],array[parent])<0){
                swap(parent, child);
                child = parent;
                parent = (child - 1) >> 1;
            } else {
                return;
            }
        }
    }

    //交换
    private void swap(int parent, int child) {
        int temp = array[parent];
        array[parent] = array[child];
        array[child] = temp;
    }

    public static void main(String[] args) {
        int[] array = {5, 3, 7, 1, 4, 6, 8, 0, 2};
        MyPriorityQueue mp = new MyPriorityQueue(array,new Greater());
        mp.offer(9);
        System.out.println(mp.peek());
        mp.offer(-1);
        System.out.println(mp.peek());
        System.out.println(mp.size());
        if (mp.isEmpty()){
            System.out.println("空");
        }else {
            System.out.println("非空");
        }
        while (!mp.isEmpty()){
            int temp=mp.poll();
            System.out.print(temp+" ");
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值