用Python实现一个优先级队列(Priority Queue),爬虫

堆(Heap)

在实现一个优先队列之前,先简单介绍 heap(堆)的概念。堆,是对于每一个父节点上的值都小于或等于子节点的值的二叉树。此外,一个堆必须是一个完整的二叉树,除了最底层其他每一级必须是被完整填充的。因此,堆的最重要的一个特点就是:首项heap[0]总是最小的一项。

而堆化(heapify)则是将一个二叉树转化为一个堆数据结构的过程。在Python中,我们可以用自带heapq模块中的heapify(x)函数来实现将一个列表 x 转化为一个堆。时间复杂度为线性O(logN). 代码如下:

Python
>>> import <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/heapq" title="View all posts in heapq" target="_blank">heapq</a></span> >>> x = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] >>> heap = list(x) >>> <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/heapq" title="View all posts in heapq" target="_blank">heapq</a></span>.heapify(heap) >>> heap [-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
1
2
3
4
5
6
7
>>> import heapq
>>> x = [ 1 , 8 , 2 , 23 , 7 , - 4 , 18 , 23 , 42 , 37 , 2 ]
>>> heap = list ( x )
>>> heapq . heapify ( heap )
>>> heap
 
[ - 4 , 2 , 1 , 23 , 7 , 2 , 18 , 23 , 42 , 37 , 8 ]

heap 是被"堆化"后的列表,heap[0] = -4为最小项。注意:此时heap 的数据类型仍是一个list。

另外,可以用heappop(), heappush(),heapreplace()等方法来对一个堆列表进行操作。例如,heappop()会从堆列表中拿出并返回最小项,并且使堆保持不变(即heap[0]仍为最小项)。

Python
>>> heapq.heappop(heap) -4 >>> heapq.heappop(heap) 1 >>> heapq.heappop(heap) 2 >>> heap [2, 7, 8, 23, 42, 37, 18, 23]
1
2
3
4
5
6
7
8
>>> heapq . heappop ( heap )
- 4
>>> heapq . heappop ( heap )
1
>>> heapq . heappop ( heap )
2
>>> heap
[ 2 , 7 , 8 , 23 , 42 , 37 , 18 , 23 ]

优先级队列(Priority Queue)
优先级队列的特点:

给定一个优先级(Priority)
每次pop操作都会返回一个拥有最高优先级的项
代码如下:

Python
import heapq class PriorityQueue(object): def __init__(self): self._<span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/queue" title="View all posts in queue" target="_blank">queue</a></span> = [] #创建一个空列表用于存放队列 self._index = 0 #指针用于记录push的次序 def push(self, item, priority): """队列由(priority, index, item)形式的元祖构成""" heapq.heappush(self._<span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/queue" title="View all posts in queue" target="_blank">queue</a></span>, (-priority, self._index, item)) self._index += 1 def pop(self): return heapq.heappop(self._queue)[-1] #返回拥有最高优先级的项 class Item(object): def __init__(self, name): self.name = name def __repr__(self): return 'Item: {!r}'.format(self.name) if __name__ == '__main__': q = PriorityQueue() q.push(Item('foo'), 5) q.push(Item('bar'), 1) q.push(Item('spam'), 3) q.push(Item('grok'), 1) for i in range(4): print(q._queue) print(q.pop())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import heapq
 
class PriorityQueue ( object ) :
     def __init__ ( self ) :
         self . _queue = [ ]          #创建一个空列表用于存放队列
         self . _index = 0          #指针用于记录push的次序
    
     def push ( self , item , priority ) :
         """队列由(priority, index, item)形式的元祖构成"""
         heapq . heappush ( self . _queue , ( - priority , self . _index , item ) )
         self . _index += 1
        
     def pop ( self ) :
         return heapq . heappop ( self . _queue ) [ - 1 ]      #返回拥有最高优先级的项
 
class Item ( object ) :
     def __init__ ( self , name ) :
         self . name = name
 
     def __repr__ ( self ) :
         return 'Item: {!r}' . format ( self . name )
 
if __name__ == '__main__' :
     q = PriorityQueue ( )
     q . push ( Item ( 'foo' ) , 5 )
     q . push ( Item ( 'bar' ) , 1 )
     q . push ( Item ( 'spam' ) , 3 )
     q . push ( Item ( 'grok' ) , 1 )
     for i in range ( 4 ) :
         print ( q . _queue )
         print ( q . pop ( ) )

对队列进行4次pop()操作,打印结果如下:

Python
[(-5, 0, Item: 'foo'), (-1, 1, Item: 'bar'), (-3, 2, Item: 'spam'), (-1, 3, Item: 'grok')] Item: 'foo' [(-3, 2, Item: 'spam'), (-1, 1, Item: 'bar'), (-1, 3, Item: 'grok')] Item: 'spam' [(-1, 1, Item: 'bar'), (-1, 3, Item: 'grok')] Item: 'bar' [(-1, 3, Item: 'grok')] Item: 'grok'
1
2
3
4
5
6
7
8
[ ( - 5 , 0 , Item : 'foo' ) , ( - 1 , 1 , Item : 'bar' ) , ( - 3 , 2 , Item : 'spam' ) , ( - 1 , 3 , Item : 'grok' ) ]
Item : 'foo'
[ ( - 3 , 2 , Item : 'spam' ) , ( - 1 , 1 , Item : 'bar' ) , ( - 1 , 3 , Item : 'grok' ) ]
Item : 'spam'
[ ( - 1 , 1 , Item : 'bar' ) , ( - 1 , 3 , Item : 'grok' ) ]
Item : 'bar'
[ ( - 1 , 3 , Item : 'grok' ) ]
Item : 'grok'

可以观察出pop()是如何返回一个拥有最高优先级的项。对于拥有相同优先级的项(bar和grok),会按照被插入队列的顺序来返回。代码的核心是利用heapq模块,之前已经说过,heapq.heappop()会返回最小值项,因此需要把 priority 的值变为负,才能让队列将每一项按从最高到最低优先级的顺序级来排序。




  • zeropython 微信公众号 5868037 QQ号 5868037@qq.com QQ邮箱
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值