PriorityQueue的详解

目录

1.PriorityQueue的特性

2.PriorityQueue接口介绍 

2.1PriorityQueue的造方式

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

3.top-k问题


1.PriorityQueue的特性

PriorityQueue的详解_第1张图片

Java 集合框架中提供了 PriorityQueue PriorityBlockingQueue 两种类型的优先级队列, PriorityQueue 是线 程不安全的, PriorityBlockingQueue 是线程安全的 ,本文主要介绍 PriorityQueue
关于 PriorityQueue 的使用要注意:
(1)使用时必须导入 PriorityQueue 所在的包,即:
import java . util . PriorityQueue ;
(2) PriorityQueue 中放置的元素必须要能够比较大小,不能插入无法比较大小的对象
举例:
    public static void main(String[] args) {
        PriorityQueue priorityQueue = new PriorityQueue<>();
         priorityQueue.offer(new Student(18,"wh"));
         priorityQueue.offer(new Student(18,"zhangshan"));
    }
public class Student {
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
会报ClassCastException异常,因为Student的比较对象不明确。
但只添加一个不会报 ClassCastException异常
public static void main(String[] args) {
        PriorityQueue priorityQueue = new PriorityQueue<>();
         priorityQueue.offer(new Student(18,"wh"));
    }

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

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

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

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

举例:

    public static void main(String[] args) {
        PriorityQueue priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(100);
        priorityQueue.offer(2);
        priorityQueue.offer(-2);
        System.out.println(priorityQueue.poll());
        System.out.println(priorityQueue.poll());
        System.out.println(priorityQueue.poll());
    }

运行结果:

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

举例:

class IntCmp implements Comparator{
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue p = new PriorityQueue<>(new IntCmp());
p.offer(4);
p.offer(3);
p.offer(2);
p.offer(1);
p.offer(5);
System.out.println(p.peek());
}
}

 运行结果:5


 

2.PriorityQueue接口介绍 

2.1PriorityQueue的造方式

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

故创建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插入/删除/获取优先级最高的元素

PriorityQueue的详解_第3张图片

(1)offer底层代码展示 

private static final long serialVersionUID = -7720805057305804111L;

private static final int DEFAULT_INITIAL_CAPACITY = 11;

 transient Object[] queue;

private int size = 0;

private final Comparator comparator;

offer:


public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

siftUp:

private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

siftUpUsingComparator:

    private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }

siftUpComparable:

 private void siftUpComparable(int k, E x) {
        Comparable key = (Comparable) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

 (2)PriorityQueue的扩容方式:

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

3.top-k问题

最小K个数icon-default.png?t=N7T8https://leetcode.cn/problems/smallest-k-lcci/PriorityQueue的详解_第4张图片

 代码:

class Solution {
       public int[] smallestK(int[] arr, int k) {
            int[] ret = new int[k];
        if (arr==null||k<=0){
            return ret;
        }
        imp imp = new imp();
        PriorityQueue priorityQueue = new PriorityQueue<>(imp);
        for (int i = 0; i < k; i++) {
            priorityQueue.offer(arr[i]);
        }

        for (int i = k; i < arr.length; i++) {
            int top=priorityQueue.peek();
            if(top>arr[i]){
                priorityQueue.poll();
                priorityQueue.offer(arr[i]);
            }
        }
        for (int i = 0; i < k; i++) {
            ret[i]=priorityQueue.poll();
        }
        return ret;
    }
}

class imp implements Comparator {
    public int compare(Integer o1,Integer o2) {
        return o2-o1;
    }
}

解析:

PriorityQueue的详解_第5张图片

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

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


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

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

你可能感兴趣的:(java,开发语言,数据结构,算法,经验分享,其他)