Weibw's World Weibw's World
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Weibw

一个没有梦想的咸鱼
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《Flask》

  • 《Python Cookbook》第三版

    • 第一章:数据结构与算法

      • 解压序列赋值给多个变量
      • 解压可迭代对象赋值给多个变量
      • 保留最后 N 个元素
      • 查找最大或最小的 N 个元素
      • 实现一个优先级队列
        • 字典中的键映射多个值
        • 字典排序
        • 字典的运算
        • 查找两字典的相同点
        • 删除序列相同元素并保持顺序
        • 命名切片
        • 序列中出现次数最多的元素
        • 通过某个关键字排序一个字典列表
        • 排序不支持原生比较的对象
        • 通过某个字段将记录分组
        • 过滤序列元素
        • 从字典中提取子集
        • 映射名称到序列元素
        • 转换并同时计算数据
        • 合并多个字典或映射
      • 第二章:字符串和文本

      • 第三章:数字日期和时间

      • 第四章:迭代器与生成器

      • 第五章:文件与IO

      • 第六章:数据编码和处理

      • 第七章:函数

      • 第八章:类与对象

      • 第九章:元编程

      • 第十章:模块与包

      • 第十一章:网络与Web编程

      • 第十二章:并发编程

      • 第十三章:脚本编程与系统管理

      • 第十四章:测试、调试和异常

      • 第十五章:C语言扩展

    • Python基础

    • Python
    • 《Python Cookbook》第三版
    • 第一章:数据结构与算法
    weibw
    2021-12-18

    实现一个优先级队列

    # 问题

    怎样实现一个按优先级排序的队列?并且在这个队列上面每次 pop 操作总是返回 优先级最高的那个元素

    # 解决方案

    提示

    下面的类利用 heapq 模块实现了一个简单的优先级队列:

    import heapq
    class PriorityQueue:
    	def __init__(self):
    		self._queue = []
    		self._index = 0
    	def push(self, item, priority):
    		heapq.heappush(self._queue, (-priority, self._index, item))
    		self._index += 1
    	def pop(self):
    		return heapq.heappop(self._queue)[-1]
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    下面是它的使用方式:

    >>> class Item:
    ... 	def __init__(self, name):
    ... 		self.name = name
    ... 	def __repr__(self):
    ... 		return 'Item({!r})'.format(self.name)
    ...
    >>> q = PriorityQueue()
    >>> q.push(Item('foo'), 1)
    >>> q.push(Item('bar'), 5)
    >>> q.push(Item('spam'), 4)
    >>> q.push(Item('grok'), 1)
    >>> q.pop()
    Item('bar')
    >>> q.pop()
    Item('spam')
    >>> q.pop()
    Item('foo')
    >>> q.pop()
    Item('grok')
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    注意

    仔细观察可以发现,第一个 pop() 操作返回优先级最高的元素。另外注意到如果 两个有着相同优先级的元素(foo 和 grok ),pop 操作按照它们被插入到队列的顺序 返回的。

    # 讨论

    这一小节我们主要关注 heapq 模块的使用。函数 heapq.heappush() 和 heapq. heappop() 分别在队列 _queue 上插入和删除第一个元素,并且队列 _queue 保证第一 个元素拥有最高优先级(1.4 节已经讨论过这个问题)。heappop() 函数总是返回”最小 的”的元素,这就是保证队列 pop 操作返回正确元素的关键。另外,由于 push 和 pop 操作时间复杂度为 O(log N),其中 N 是堆的大小,因此就算是 N 很大的时候它们运行 速度也依旧很快。

    在上面代码中,队列包含了一个 (-priority, index, item) 的元组。优先级为负 数的目的是使得元素按照优先级从高到低排序。这个跟普通的按优先级从低到高排序 的堆排序恰巧相反。

    index 变量的作用是保证同等优先级元素的正确排序。通过保存一个不断增加的 index 下标变量,可以确保元素按照它们插入的顺序排序。而且,index 变量也在相同 优先级元素比较的时候起到重要作用。 为了阐明这些,先假定 Item 实例是不支持排序的:

    >>> a = Item('foo')
    >>> b = Item('bar')
    >>> a < b
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: unorderable types: Item() < Item()
    >>>
    
    1
    2
    3
    4
    5
    6
    7

    如果你使用元组 (priority, item) ,只要两个元素的优先级不同就能比较。但是 如果两个元素优先级一样的话,那么比较操作就会跟之前一样出错:

    >>> a = (1, Item('foo'))
    >>> b = (5, Item('bar'))
    >>> a < b
    True
    >>> c = (1, Item('grok'))
    >>> a < c
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: unorderable types: Item() < Item()
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    通过引入另外的 index 变量组成三元组 (priority, index, item) ,就能很好的 避免上面的错误,因为不可能有两个元素有相同的 index 值。Python 在做元组比较时 候,如果前面的比较已经可以确定结果了,后面的比较操作就不会发生了:

    >>> a = (1, 0, Item('foo'))
    >>> b = (5, 1, Item('bar'))
    >>> c = (1, 2, Item('grok'))
    >>> a < b
    True
    >>> a < c
    True
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8

    如果你想在多个线程中使用同一个队列,那么你需要增加适当的锁和信号量机制。 可以查看 12.3 小节的例子演示是怎样做的。

    heapq 模块的官方文档有更详细的例子程序以及对于堆理论及其实现的详细说明。

    编辑 (opens new window)
    #Python
    上次更新: 2023/10/13, 17:39:25
    查找最大或最小的 N 个元素
    字典中的键映射多个值

    ← 查找最大或最小的 N 个元素 字典中的键映射多个值→

    最近更新
    01
    牛客网非技术快速入门SQL练习题
    03-08
    02
    其他日常SQL题
    03-07
    03
    用户与权限管理
    03-05
    更多文章>
    Theme by Vdoing | Copyright © 2021-2023 | Weibw | 辽ICP备18015889号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式