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]

 

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