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

简要概括

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

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

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

实现构造

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

PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); 

 2.实现大顶堆,容量11

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

API文档 

构造方法摘要

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

示例算法

 Leetcode中:选择最大的K个数

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

public class findTopK {

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章