当前位置:   article > 正文

优先队列PriorityQueue (大根堆/小根堆/TopK问题)_优先队列默认是小顶堆吗

优先队列默认是小顶堆吗

        PriorityQueue是从JDK1.5开始提供的新的数据结构接口,它是一种基于优先级堆的极大优先级队列。优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。

        默认情况下,PriorityQueue是小顶堆,如代码所示

  1. public static void main(String[] args) {
  2. PriorityQueue<Integer> queue = new PriorityQueue<>();
  3. queue.offer(1);
  4. queue.offer(2);
  5. queue.offer(3);
  6. queue.offer(4);
  7. queue.offer(5);
  8. queue.offer(6);
  9. while (!queue.isEmpty()){
  10. System.out.print(queue.poll() + " ");
  11. }
  12. }

        输出结果:

        我们也可以通过以下方式来构造大顶堆

  1. public static void main(String[] args) {
  2. PriorityQueue<Integer> queue = new PriorityQueue<>((o1,o2) -> o2 - o1);//降序
  3. queue.offer(1);
  4. queue.offer(2);
  5. queue.offer(3);
  6. queue.offer(4);
  7. queue.offer(5);
  8. queue.offer(6);
  9. while (!queue.isEmpty()){
  10. System.out.print(queue.poll() + " ");
  11. }
  12. }

        输出结果:

         Top K问题,力扣347和力扣692:

力扣347:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

        代码如下:注意构造小顶堆的时候(o1,o2)-> o1.getValue() - o2.getValue() 不能省略。

  1. public int[] topKFrequent(int[] nums, int k) {
  2. //key为元素值,value为出现频率
  3. HashMap<Integer,Integer> map = new HashMap<>();
  4. PriorityQueue<Map.Entry<Integer, Integer>> queue
  5. = new PriorityQueue<>((o1,o2)-> o1.getValue() - o2.getValue());
  6. int[] res = new int[k];
  7. for (int num : nums) {
  8. map.put(num,map.getOrDefault(num,0) + 1);
  9. }
  10. Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
  11. for (Map.Entry<Integer, Integer> entry : entries) {
  12. queue.offer(entry);
  13. if(queue.size() > k){
  14. queue.poll();
  15. }
  16. }
  17. //留下的都是出现频率最高的
  18. for(int i = 0; i < k; i++){
  19. Map.Entry<Integer, Integer> poll = queue.poll();
  20. res[i] = poll.getKey();
  21. }
  22. return res;

力扣692:给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序排序

示例:

输入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。注意,按字母顺序 "i" 在 "love" 之前。

        这题比上题难一点,因为当两个单词出现次数一致时还要考虑按字典序排序,其次是答案需要从高到底排序,这里主要体现在优先队列PriorityQueue的构造上。代码如下:

  1. public List<String> topKFrequent(String[] words, int k) {
  2. List<String> res = new ArrayList<>();
  3. //key为元素,value为出现频率
  4. HashMap<String,Integer> map = new HashMap<>();
  5. for (String word : words) {
  6. map.put(word,map.getOrDefault(word,0) + 1);
  7. }
  8. PriorityQueue<Map.Entry<String,Integer>> queue = new PriorityQueue<>(
  9. ((o1, o2) -> {
  10. if(o1.getValue() == o2.getValue()){
  11. return o2.getKey().compareTo(o1.getKey());
  12. }
  13. return o1.getValue() - o2.getValue();
  14. })
  15. );
  16. Set<Map.Entry<String, Integer>> entries = map.entrySet();
  17. for (Map.Entry<String, Integer> entry : entries) {
  18. queue.offer(entry);
  19. if(queue.size() > k){
  20. queue.poll();
  21. }
  22. }
  23. for(int i = 0; i < k; i++){
  24. res.add(queue.poll().getKey());
  25. }
  26. Collections.reverse(res);
  27. return res;
  28. }

        注意o2.getKey().compareTo(o1.getKey())是按字典倒序,为什么要这么做呢,是因为我们这里用到小顶堆,所以每次poll出来的都是最小频率元素,最后需要reverse一下,为了配合这个,所以我们构造优先队列的时候采用字典倒序。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/355159
推荐阅读
  

闽ICP备14008679号