Python 内置优先队列PriorityQueue 高级餐厅用餐场景展示

正式的Python专栏第64篇,同学站住,别错过这个从0开始的文章!

前面学委说要把内置队列都撸一撸,前面展示了有简单的先进后出,先进先出队列。

今天把优先队列先展示了。

PriorityQueue

这是一个懂得分辨轻重缓急的队列。 之前FIFO/FILO这些都是按照放入顺序,先放进去的要么先出队,要么后面出队。

实际应用场景跟我们日常类似,比如我们去一个高级餐厅吃饭。

通常他们会设置会员等级,比如常客VIP,或者那种高级VIP(VVIP),这些入队。

前台服务人员就会根据客户登记安排客户进场。

这时候优先队列就派上用场。

优先队列可以放入元素格式如下:


q = PriorityQueue()
# 二元组(优先级数,数据 )
q.put((3, '小白'))

下面是模拟整个队列排队:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/2/14 11:13 下午
# @Author : LeiXueWei
# @优快云/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : priorityqdemo.py
# @Project : hello

from queue import PriorityQueue

q = PriorityQueue()

q.put((3, '小白'))
#后到
q.put((2, '雷学委'))
#最后到
q.put((1, '小花'))

while not q.empty():
    next_item = q.get()
    print("🐰 欢迎 %s 用餐:" % str(next_item))

首先,小白没有VIP先到拿号了。 然后学委,小花陆续去餐厅排队。

直接运行代码,可以看到小花同学最后到场,但是她缺第一个进去餐厅内堂用餐了。

没办法,她是VVIP,级别最高(第三个元素的数值最小)所以放到最前面了。

效果图如下:

屏幕快照 2022-02-14 下午11.47.28.png

所以就很‘合理’(没办法,谁叫你去高级餐厅排队,去个普通的餐厅,我们就用普通FIFO队列来管理用餐秩序了)。

优先队列怎么排队的?

打开queue这个库直接看到PriorityQueue这个类源码:

屏幕快照 2022-02-14 下午11.52.11.png

太简单了,直接继承了Queue父类。

不过我们看到优先队列覆盖了_put方法,用了heappush方法来放元素到二叉堆(这个是在heapq内置库里面的一个方法,也有取元素的实现)。

def heappush(heap, item):
    """Push item onto heap, maintaining the heap invariant."""
    heap.append(item)
    _siftdown(heap, 0, len(heap)-1)
    

headpush内部直接把新入队的元素放到队尾(前面heap=[])

然后执行下面的方法摆放元素:

def _siftdown(heap, startpos, pos):
    newitem = heap[pos]
    # Follow the path to the root, moving parents down until finding a place
    # newitem fits.
    while pos > startpos:
        parentpos = (pos - 1) >> 1
        parent = heap[parentpos]
        if newitem < parent:
            heap[pos] = parent
            pos = parentpos
            continue
        break
    heap[pos] = newitem

这里使用[最小二叉堆(https://baike.baidu.com/item/%E6%9C%80%E5%B0%8F%E5%A0%86) ,通过不断与父节点对比(父节点的位置为parentpos = (pos - 1) >> 1)。

循环比对,如果新加元素小于父节点,当前新加节点上移(也就是父节点下移到新节点每次放入的新位置)

直到找到一个父节点是小于新节点值的位置,停止移动,入队操作完毕。

这一段比较烧脑,先解释这个入队。后面再做一个图形展示一下。

总结

优先队列,就像高级餐厅或者银行排队VIP/VVIP这种,特殊人群特殊安排。

内部实现用了二叉树这个数据结构,后面学委再做图展示。

前篇学委说了这个, 再次放在一起,比对回顾:

后进先出队列,很像超市货柜,后面放的物品,先被消费者看到。

先进先出队列,就像大家排队体检,排队打饭一样。肯定是先到的先安排。

优先队列,就像高级餐厅或者银行排队VIP/VVIP这种,特殊人群特殊安排。

喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏

持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!

### Java 中 PriorityQueue 的使用方法 #### 什么是 PriorityQueue? `PriorityQueue` 是 Java 集合框架的一部分,位于 `java.util` 包中。它是一个基于堆结构的无界队列,默认情况下实现最小堆(min-heap),即每次取出的是当前队列中优先级最低的对象。 #### 构造函数 以下是常见的几种构造方式: 1. **默认构造函数** 创建一个按照自然顺序排列的优先队列。 ```java PriorityQueue<Integer> pq = new PriorityQueue<>(); ``` 2. **指定初始容量** 可以为队列分配初始容量。 ```java PriorityQueue<Integer> pq = new PriorityQueue<>(initialCapacity); ``` 3. **自定义比较器** 如果对象不支持自然排序或者需要特定的排序逻辑,可以通过传入 `Comparator` 来定制排序规则[^1]。 ```java PriorityQueue<Integer> minHeap = new PriorityQueue<>((a, b) -> a - b); PriorityQueue<String> customOrder = new PriorityQueue<>((s1, s2) -> s2.length() - s1.length()); ``` #### 常见方法及其说明 | 方法名 | 描述 | |---------------------|--------------------------------------------------------------------------------------| | `add(E e)` | 将指定元素插入此优先队列。如果成功则返回 true;否则抛出异常。 | | `offer(E e)` | 功能同 `add()`,但在失败时不会抛出异常而是返回 false。 | | `remove(Object o)` | 删除队列中的某个对象实例。如果找到并删除,则返回 true;否则返回 false。 | | `poll()` | 获取并移除队列头部的元素(具有最高优先级的元素)。如果没有元素存在,则返回 null。 | | `peek()` | 返回但不移除队列头部的元素。如果没有元素存在,则返回 null。 | | `size()` | 返回队列中的元素数量。 | | `comparator()` | 返回用于对此队列进行排序的 Comparator 实例。如果使用自然顺序创建,则返回 null[^2]。 | #### 示例代码 下面展示如何使用 `PriorityQueue` 并结合自定义比较器: ```java import java.util.PriorityQueue; import java.util.Comparator; public class Main { public static void main(String[] args) { // 默认按升序排列 (最小堆) PriorityQueue<Integer> minHeap = new PriorityQueue<>(); minHeap.add(5); minHeap.add(10); minHeap.add(1); System.out.println("Min Heap Poll: " + minHeap.poll()); // 输出 1 // 自定义最大堆 PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2.compareTo(o1); // 改变方向形成最大堆 } }); maxHeap.offer(5); maxHeap.offer(10); maxHeap.offer(1); System.out.println("Max Heap Peek: " + maxHeap.peek()); // 输出 10 } } ``` 上述例子展示了两种不同类型的堆:一种是最小堆,另一种通过自定义比较器实现了最大堆。 --- #### 注意事项 1. **线程安全性** `PriorityQueue` 不是线程安全的数据结构。如果多个线程同时访问同一个队列,需手动同步操作。 2. **null 和不可比较对象** 队列不允许存储 `null` 元素,并且所有元素都应可相互比较。如果不满足这些条件,在运行时会引发错误。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雷学委

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值