【算法】优先级队列-基础与应用

优先级队列(Priority Queue)是一种特殊的队列类型,它允许在其元素中分配优先级。与传统的先进先出(FIFO)队列不同,优先级队列中元素的出队顺序取决于它们的优先级。优先级较高的元素会被优先处理,即使它们是在优先级较低的元素之后被加入队列的。

优先级队列的特点:

  • 插入操作:新元素被添加到队列中时,它们根据自身的优先级被放置在适当的位置。
  • 移除操作:优先级队列通常移除并返回具有最高优先级的元素。
  • 查询操作:可以查询具有最高优先级的元素,而不从队列中移除它。

在Java中的实现:

Java标准库中的java.util.PriorityQueue类提供了一个基于优先级的队列实现。PriorityQueue底层使用了一种称为"堆"的数据结构,通常是二叉堆,以确保高效地维护元素的优先级顺序。

java 复制代码
import java.util.PriorityQueue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个优先级队列
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();

        // 插入元素
        priorityQueue.add(5);
        priorityQueue.add(1);
        priorityQueue.add(3);
        priorityQueue.add(4);
        priorityQueue.add(2);

        // 查看并移除优先级最高的元素
        while (!priorityQueue.isEmpty()) {
            System.out.println(priorityQueue.poll());
        }
    }
}

在这个例子中,PriorityQueue默认使用元素的自然排序(对于基本类型或实现了Comparable接口的对象)。如果需要自定义排序规则,可以通过构造函数传递一个Comparator实例。

自定义排序:

java 复制代码
import java.util.Comparator;
import java.util.PriorityQueue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个优先级队列,使用自定义比较器
        PriorityQueue<String> priorityQueue = 
            new PriorityQueue<>(new Comparator<String>() {
                @Override
                public int compare(String s1, String s2) {
                    return s2.compareTo(s1); // 反向排序
                }
            });

        // 插入元素
        priorityQueue.add("Z");
        priorityQueue.add("A");
        priorityQueue.add("C");

        // 查看并移除优先级最高的元素
        while (!priorityQueue.isEmpty()) {
            System.out.println(priorityQueue.poll());
        }
    }
}

性能:

PriorityQueue提供了高效的插入和移除操作,时间复杂度通常为O(log n),其中n是队列中的元素数量。这是因为堆数据结构能够有效地维护元素之间的优先级关系,同时保持操作效率。

大顶堆/小顶堆

前K个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素

示例 1:

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

输出: [1,2]

思路:

    1. 统计元素出现的频率
    1. 对频率进行排序
    1. 找出前k个高频元素

构建一个优先级队列【小顶堆】,遍历map,将二元组存入小顶堆中【以频率进行排序】,维护优先级队列的长度为k,当有比小顶堆顶堆大的元素,直接弹出堆顶并加入新的节点。最后优先级队列中保存的就是前k高频的元素,直接弹出即可。

java 复制代码
 public int[] topKFrequent(int[] nums, int k) {

    //1.使用map统计元素出现频率
    HashMap<Integer,Integer> map =  new HashMap<>();
    for(int num : nums){
        map.put(num,map.getOrDefault(num,0) + 1);
    }

    //2.将map中的元素以二元组的形式放入优先级队列中,并以频率为目标构建小顶堆
    PriorityQueue<int[]> queue = new PriorityQueue<>((pair1, pair2) ->
            pair1[1] - pair2[1]);
    //遍历map,放入优先级队列中
    for (Entry<Integer, Integer> entry : map.entrySet()){
        //小顶堆的大小小于k,直接放入
        if (queue.size() < k){
            queue.add(new int[]{entry.getKey(),entry.getValue()});
        }else {
            //小顶堆的大小大于k,与堆顶比较,如果大于堆顶,则弹出堆顶并加入堆
            if (queue.peek()[1] < entry.getValue()){
                queue.poll();
                queue.add(new int[]{entry.getKey(),entry.getValue()});
            }
        }
    }

    //3.依次弹出小顶堆中的key
    int[] res =  new int[k];
    int size = queue.size();
    for (int i = 0; i < size; i++) {
        res[i] = queue.poll()[0];
    }

    return res;

}
相关推荐
深邃-几秒前
【数据结构与算法】-二叉树(1):树的概念与结构,二叉树的概念与结构
数据结构·算法·链表·二叉树··顺序表
lsx2024064 分钟前
Go 语言范围(Range)
开发语言
初心未改HD5 分钟前
Go语言同步原语Mutex、WaitGroup、Once深度解析
开发语言·golang
风筝在晴天搁浅8 分钟前
手撕归并排序
数据结构·算法·排序算法
摇滚侠9 分钟前
Public Key Retrieval is not allowed
java·数据库·mysql
lynnlovemin11 分钟前
C++高精度加减乘除算法详解
开发语言·c++·算法·高精度
计算机学姐12 分钟前
基于微信小程序的宠物服务系统【uniapp+springboot+vue】
java·vue.js·spring boot·mysql·微信小程序·uni-app·宠物
lst042612 分钟前
Maven 构建命令
java·maven
原来是猿13 分钟前
算法中 cin/cout 超时?聊聊它与 printf/scanf 的性能差异
算法
梅孔立13 分钟前
Aspose.Words Java 表格动态删列、合并列、表头重建、全局字体统一解决方案
java·开发语言·word·aspose·在线编辑