• PriorityQueue的详解


    目录

    1.PriorityQueue的特性

    2.PriorityQueue接口介绍 

    2.1PriorityQueue的造方式

     2.2插入/删除/获取优先级最高的元素

    3.top-k问题


    1.PriorityQueue的特性

    Java 集合框架中提供了 PriorityQueue PriorityBlockingQueue 两种类型的优先级队列, PriorityQueue 是线 程不安全的, PriorityBlockingQueue 是线程安全的 ,本文主要介绍 PriorityQueue
    关于 PriorityQueue 的使用要注意:
    (1)使用时必须导入 PriorityQueue 所在的包,即:
    import java . util . PriorityQueue ;
    (2) PriorityQueue 中放置的元素必须要能够比较大小,不能插入无法比较大小的对象
    举例:
    1. public static void main(String[] args) {
    2. PriorityQueue priorityQueue = new PriorityQueue<>();
    3. priorityQueue.offer(new Student(18,"wh"));
    4. priorityQueue.offer(new Student(18,"zhangshan"));
    5. }
    1. public class Student {
    2. private int age;
    3. private String name;
    4. public Student(int age, String name) {
    5. this.age = age;
    6. this.name = name;
    7. }
    8. public int getAge() {
    9. return age;
    10. }
    11. public void setAge(int age) {
    12. this.age = age;
    13. }
    14. public String getName() {
    15. return name;
    16. }
    17. public void setName(String name) {
    18. this.name = name;
    19. }
    20. @Override
    21. public String toString() {
    22. return "Student{" +
    23. "age=" + age +
    24. ", name='" + name + '\'' +
    25. '}';
    26. }
    27. }
    会报ClassCastException异常,因为Student的比较对象不明确。
    但只添加一个不会报 ClassCastException异常
    1. public static void main(String[] args) {
    2. PriorityQueue priorityQueue = new PriorityQueue<>();
    3. priorityQueue.offer(new Student(18,"wh"));
    4. }

    因为只添加一个,不用比较

    (3)不能插入null对象,否则会抛出NullPointerException

    (4)没有容量限制,可以插入任意多个元素,其内部可以自动扩容

    (5)PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素,如果需要大堆需要用户提供比较器

    举例:

    1. public static void main(String[] args) {
    2. PriorityQueue priorityQueue = new PriorityQueue<>();
    3. priorityQueue.offer(100);
    4. priorityQueue.offer(2);
    5. priorityQueue.offer(-2);
    6. System.out.println(priorityQueue.poll());
    7. System.out.println(priorityQueue.poll());
    8. System.out.println(priorityQueue.poll());
    9. }

    运行结果:

     如果需要大堆需要用户提供比较器

    举例:

    1. class IntCmp implements Comparator{
    2. @Override
    3. public int compare(Integer o1, Integer o2) {
    4. return o2-o1;
    5. }
    6. }
    7. public class TestPriorityQueue {
    8. public static void main(String[] args) {
    9. PriorityQueue p = new PriorityQueue<>(new IntCmp());
    10. p.offer(4);
    11. p.offer(3);
    12. p.offer(2);
    13. p.offer(1);
    14. p.offer(5);
    15. System.out.println(p.peek());
    16. }
    17. }

     运行结果:5


     

    2.PriorityQueue接口介绍 

    2.1PriorityQueue的造方式

    此处只是列出了 PriorityQueue 中常见的几种构造方式
    (1)PriorityQueue()的底层代码
    1. private static final int DEFAULT_INITIAL_CAPACITY = 11;
    2. public PriorityQueue() {
    3. this(DEFAULT_INITIAL_CAPACITY, null);
    4. }

    故创建PriorityQueue()时数组的默认容量是11;

    (2)PriorityQueue(Collectionextends E> c)的举例使用

    ArrayList list = new ArrayList<>();
    list.add(4);
    list.add(3);
    list.add(2);
    list.add(1);

    // 用ArrayList对象来构造一个优先级队列的对象
    // q中已经包含了三个元素
    PriorityQueue q = new PriorityQueue<>(list);
    System.out.println(q.size());
    System.out.println(q.peek());

     2.2插入/删除/获取优先级最高的元素

    (1)offer底层代码展示 

    1. private static final long serialVersionUID = -7720805057305804111L;
    2. private static final int DEFAULT_INITIAL_CAPACITY = 11;
    3. transient Object[] queue;
    4. private int size = 0;
    5. private final Comparatorsuper E> comparator;

    offer:

    1. public boolean offer(E e) {
    2. if (e == null)
    3. throw new NullPointerException();
    4. modCount++;
    5. int i = size;
    6. if (i >= queue.length)
    7. grow(i + 1);
    8. size = i + 1;
    9. if (i == 0)
    10. queue[0] = e;
    11. else
    12. siftUp(i, e);
    13. return true;
    14. }

    siftUp:

    1. private void siftUp(int k, E x) {
    2. if (comparator != null)
    3. siftUpUsingComparator(k, x);
    4. else
    5. siftUpComparable(k, x);
    6. }

    siftUpUsingComparator:

    1. private void siftUpUsingComparator(int k, E x) {
    2. while (k > 0) {
    3. int parent = (k - 1) >>> 1;
    4. Object e = queue[parent];
    5. if (comparator.compare(x, (E) e) >= 0)
    6. break;
    7. queue[k] = e;
    8. k = parent;
    9. }
    10. queue[k] = x;
    11. }

    siftUpComparable:

    1. private void siftUpComparable(int k, E x) {
    2. Comparablesuper E> key = (Comparablesuper E>) x;
    3. while (k > 0) {
    4. int parent = (k - 1) >>> 1;
    5. Object e = queue[parent];
    6. if (key.compareTo((E) e) >= 0)
    7. break;
    8. queue[k] = e;
    9. k = parent;
    10. }
    11. queue[k] = key;
    12. }

     (2)PriorityQueue的扩容方式:

    1. private void grow(int minCapacity) {
    2. int oldCapacity = queue.length;
    3. // Double size if small; else grow by 50%
    4. int newCapacity = oldCapacity + ((oldCapacity < 64) ?
    5. (oldCapacity + 2) :
    6. (oldCapacity >> 1));
    7. // overflow-conscious code
    8. if (newCapacity - MAX_ARRAY_SIZE > 0)
    9. newCapacity = hugeCapacity(minCapacity);
    10. queue = Arrays.copyOf(queue, newCapacity);
    11. }
    优先级队列的扩容说明:
    如果容量小于 64 时,是按照 oldCapacity 2 倍方式扩容的
    如果容量大于等于 64 ,是按照 oldCapacity 1.5 倍方式扩容的
    如果容量超过 MAX_ARRAY_SIZE ,按照 MAX_ARRAY_SIZE 来进行扩容

     代码:

    1. class Solution {
    2. public int[] smallestK(int[] arr, int k) {
    3. int[] ret = new int[k];
    4. if (arr==null||k<=0){
    5. return ret;
    6. }
    7. imp imp = new imp();
    8. PriorityQueue priorityQueue = new PriorityQueue<>(imp);
    9. for (int i = 0; i < k; i++) {
    10. priorityQueue.offer(arr[i]);
    11. }
    12. for (int i = k; i < arr.length; i++) {
    13. int top=priorityQueue.peek();
    14. if(top>arr[i]){
    15. priorityQueue.poll();
    16. priorityQueue.offer(arr[i]);
    17. }
    18. }
    19. for (int i = 0; i < k; i++) {
    20. ret[i]=priorityQueue.poll();
    21. }
    22. return ret;
    23. }
    24. }
    25. class imp implements Comparator {
    26. public int compare(Integer o1,Integer o2) {
    27. return o2-o1;
    28. }
    29. }

    解析:

    TOP-K 问题:即求数据集合中前 K 个最大的元素或者最小的元素,一般情况下数据量都比较大
    对于 Top-K 问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了 ( 可能数据都 不能一下子全部加载到内存中) 。最佳的方式就是用堆来解决,基本思路如下:

    将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。 


    以上为我个人的小分享,如有问题,欢迎讨论!!! 

    都看到这了,不如关注一下,给个免费的赞 

  • 相关阅读:
    vue面试题(持续更新)
    笙默考试管理系统-MyExamTest----codemirror(28)
    海外商城小程序为什么这么受欢迎?
    Vue响应式系统原理并实现一个双向绑定
    LNMP架构介绍及配置--部署Discuz社区论坛与wordpress博客
    第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(昆明),签到题3题
    程序员脱单
    cocos creator实现浏览星球的功能,附源码
    bash: /usr/bin/cp: Argument list too long Linux 系统大量数据移动复制出错
    【m98】接收udp包到变为CopyOnWriteBuffer的rtp包及call模块传递的过程
  • 原文地址:https://blog.csdn.net/WHabc2002/article/details/133811708