【Java集合夜话】第8篇上:PriorityQueue优先队列详解,从源码到实战,一文吃透堆数据结构(建议收藏)

🔥 本文深入剖析Java中的优先队列PriorityQueue,从堆的基本概念到源码实现原理,带你全面理解这个重要的数据结构。由于内容较多,分为上下两篇,本篇是上篇,主要讲解基础概念和源码分析。

📚 系列专栏推荐:

积极

1. 优先队列基础

1.1 什么是优先队列?

想象你正在医院的急诊室。虽然病人按到达顺序排队,但突然来了一位急重症病人,医生会优先处理这位病人。这就是现实生活中的"优先队列":不是先来先服务,而是按照优先级处理

1.1.1 与普通队列的区别

普通队列就像我们排队买奶茶:

  • 先来的人先买
  • 后来的人后买
  • 严格遵循"先进先出"(FIFO)原则

而优先队列则像医院的急诊室:

  • 不是先来先服务
  • 而是按照事件的紧急程度
  • 优先级高的先处理
  • 优先级相同时,先来先服务

让我们用代码来直观感受一下区别:

// 普通队列
Queue<String> normalQueue = new LinkedList<>();
normalQueue.offer("小明");
normalQueue.offer("小红");
normalQueue.offer("小张");
// 处理顺序:小明 -> 小红 -> 小张

// 优先队列
PriorityQueue<Patient> emergencyRoom = new PriorityQueue<>((p1, p2) -> 
    p2.getEmergencyLevel() - p1.getEmergencyLevel());
emergencyRoom.offer(new Patient("小明", 1)); // 普通感冒
emergencyRoom.offer(new Patient("小红", 3)); // 高烧
emergencyRoom.offer(new Patient("小张", 2)); // 扭伤
// 处理顺序:小红(高烧) -> 小张(扭伤) -> 小明(感冒)
1.1.2 优先级的概念

优先级可以基于多种规则:

  1. 自然顺序
  • 数字:越小越优先
  • 字符串:字典序越小越优先
// 数字优先队列(小顶堆)
PriorityQueue<Integer> numbers = new PriorityQueue<>();
numbers.offer(3);
numbers.offer(1);
numbers.offer(2);
System.out.println(numbers.poll()); // 输出1
  1. 自定义顺序
  • 根据业务需求定义优先级
  • 通过Comparator实现自定义排序
// 工作任务队列(按优先级排序)
PriorityQueue<Task> taskQueue = new PriorityQueue<>((t1, t2) -> {
   
   
    // 先比较优先级
    if (t1.getPriority() != t2.getPriority()) {
   
   
        return t2.getPriority() - t1.getPriority();
    }
    // 优先级相同,比较创建时间
    return t1.getCreateTime().compareTo(t2.getCreateTime());
});
1.1.3 实际应用场景

优先队列在我们的日常生活和系统开发中随处可见:

  1. 操作系统的进程调度
  • 高优先级进程优先获得CPU时间片
  • 系统进程优先级高于用户进程
  • 前台进程优先级高于后台进程
  1. 打印机任务队列
  • 紧急文件优先打印
  • 老板的文件优先级更高
  • 大文件可能优先级较低
  1. 游戏排位匹配系统
class Player {
   
   
    private String name;
    private int ranking;
    private long waitTime;
    // ... 其他属性
}

PriorityQueue<Player> matchQueue = new PriorityQueue<>((p1, p2) -> {
   
   
    // 等待时间越长,优先级越高
    long timeDiff = p2.getWaitTime() - p1.getWaitTime();
    if (timeDiff != 0) {
   
   
        return (int)timeDiff;
    }
    // 等待时间相同,按照排位分数匹配
    return Math.abs(p1.getRanking() - targetRanking) - 
           Math.abs(p2.getRanking() - targetRanking);
});
  1. 网络请求处理
  • VIP用户请求优先处理
  • 支付请求优先于查询请求
  • 实时性要求高的请求优先

通过这些例子,我们可以看到优先队列的核心特点:

  • 动态调整处理顺序
  • 基于优先级的灵活排序
  • 在插入时自动维护顺序
  • 保证每次取出的都是当前最优先的元素

理解了优先队列的本质,我们就能更好地在实际开发中运用它,设计出更合理的系统。接下来,我们将深入探讨它的底层实现原理——堆数据结构。

1.2 底层数据结构:堆

要理解优先队列,我们必须先理解它的底层数据结构——堆。想象一个公司的组织架构:CEO在最顶端,下面是经理,再下面是普通员工。堆的结构也是类似的层级关系。

1.2.1 什么是堆?

堆是一种特殊的完全二叉树,它满足以下特性:

  • 结构性:是一个完全二叉树
  • 有序性:任意节点的值总是大于(或小于)其子节点的值

就像公司架构:

  • 完全二叉树:每层都尽可能填满,新人从左到右依次加入
  • 有序性:职级高的总是在上层(类比大顶堆)
1.2.2 最大堆vs最小堆
  1. 最大堆(大顶堆)
  • 父节点的值总是大于或等于子节点
  • 堆顶是最大元素
// 最大堆示例
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
maxHeap.offer(1);
maxHeap.offer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值