Java之PriorityQueue实现最大堆、最小堆

简要概括

学习很多算法知识,力争做到最优解的学习过程中,很多时候都会遇到PriorityQueue(优先队列)。一个基于优先级堆的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。优先级队列不允许使用 null 元素。依靠自然顺序的优先级队列还不允许插入不可比较的对象,这样做可能导致 ClassCastException。

此队列的头是按指定排序方式确定的最小元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列获取操作 poll、remove、peek 和 element 访问处于队列头的元素。优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组大小。它通常至少等于队列的大小。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。

此类及其迭代器实现了Collection和Iterator接口的所有可选方法。方法 iterator() 中提供的迭代器不保证以任何特定的顺序遍历优先级队列中的元素。如果需要按顺序遍历,请考虑使用 Arrays.sort(pq.toArray())。此实现不是同步的,如果多个线程中的任意线程修改了队列,则这些线程不应同时访问PriorityQueue实例。相反,请使用线程安全的PriorityBlockingQueue 类。

实现构造

1.实现小顶堆,默认容量为11

PriorityQueue minHeap = new PriorityQueue(); 

 2.实现大顶堆,容量11

PriorityQueue maxHeap = new PriorityQueue(11,new Comparator(){ 
    @Override
    public int compare(Integer i1,Integer i2){
        return i2-i1;
    }
});

API文档 

构造方法摘要

PriorityQueue()
          使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(Collection c)
          创建包含指定 collection 中元素的 PriorityQueue
PriorityQueue(int initialCapacity)
          使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(int initialCapacity, Comparator comparator)
          使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器对元素进行排序。
PriorityQueue(PriorityQueue c)
          创建包含指定优先级队列元素的 PriorityQueue
PriorityQueue(SortedSet c)
          创建包含指定有序 set 元素的 PriorityQueue
方法摘要
 boolean add(E e)
          将指定的元素插入此优先级队列。
 void clear()
          从此优先级队列中移除所有元素。
 Comparator comparator()
          返回用来对此队列中的元素进行排序的比较器;如果此队列根据其元素的自然顺序进行排序,则返回 null
 boolean contains(Object o)
          如果此队列包含指定的元素,则返回 true
 Iterator iterator()
          返回在此队列中的元素上进行迭代的迭代器。
 boolean offer(E e)
          将指定的元素插入此优先级队列。
 E peek()
          获取但不移除此队列的头;如果此队列为空,则返回 null。
 E poll()
          获取并移除此队列的头,如果此队列为空,则返回 null。
 boolean remove(Object o)
          从此队列中移除指定元素的单个实例(如果存在)。
 int size()
          返回此 collection 中的元素数。
 Object[] toArray()
          返回一个包含此队列所有元素的数组。
T[]
toArray(T[] a)
          返回一个包含此队列所有元素的数组;返回数组的运行时类型是指定数组的类型。

示例算法

 Leetcode中:选择最大的K个数

用PriorityQueue默认是自然顺序排序,要选择最大的k个数,构造小顶堆,每次取数组中剩余数与堆顶的元素进行比较,如果新数比堆顶元素大,则删除堆顶元素,并添加这个新数到堆中。

public class findTopK {

    // 找出前k个最大数,采用小顶堆实现
    public static int[] findKMax(int[] nums, int k) {
        // 队列默认自然顺序排列,小顶堆,不必重写compare
        PriorityQueue pq = new PriorityQueue<>(k);

        for (int num : nums) {
            if (pq.size() < k) {
                pq.offer(num);
            } else if (pq.peek() < num) {
                // 如果堆顶元素 < 新数,则删除堆顶,加入新数入堆
                pq.poll();
                pq.offer(num);
            }
        }

        int[] result = new int[k];
        for (int i = 0; i < k && !pq.isEmpty(); i++) {
            result[i] = pq.poll();
        }
        return result;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{1, 6, 3, 2, 5, 4, 8, 9, 7};
        System.out.println(Arrays.toString(findKMax(arr, 5)));
    }
}

输出结果:

[5, 6, 7, 8, 9]

 Leetcode中:选择最小的K个数

要选择最小的K个数使用大顶堆,每次取数组中剩余数与堆顶的元素进行比较,如果新数比堆顶元素小,则删除堆顶元素,并添加这个新数到堆中。

public class findTopK {

    // 要找前k个最小数,则构建大顶堆,要重写compare方法
    public static int[] findKMin(int[] nums, int k) {
        PriorityQueue pq = new PriorityQueue<>(k, new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int num : nums) {
            if (pq.size() < k) {
                pq.offer(num);
            } else if (pq.peek() > num) {
                // 如果堆顶元素 > 新数,则删除堆顶,加入新数入堆
                pq.poll();
                pq.offer(num);
            }
        }

        int[] result = new int[k];
        for (int i = 0; i < k && !pq.isEmpty(); i++) {
            result[i] = pq.poll();
        }
        return result;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{1, 6, 3, 2, 5, 4, 8, 9, 7};
        System.out.println(Arrays.toString(findKMin(arr, 5)));
    }
}

输出结果:

[5, 4, 3, 2, 1]

 

你可能感兴趣的:(Java学习,java,算法,PriorityQueue,最大堆,最小堆)