Python实现优先队列

Python有队列类Queue,为啥就不提供个PriorityQueue类呢?

写优先队列也是在写爬虫的时候想到的,当时没想用PageRank算法(最终也没用),就直接用优先队列来放URL,但是发现Python没有优先队列。

网上我看到一哥们用Python的bisect包来实现优先队列的

具体的网址:http://www.kgblog.net/2009/04/25/pythonSpider.html

我们就来分析下他的优先队列算法复杂度吧,这仅仅是学术探讨,没有任何别的意思。

首先在元素插入队列的时候,bisect的原理是用二分来搜索需要插入的位置,然后将后面的元素平移一个位置,将该位置空出来给需要插入的元素

看bisect包的源码:

[python]  view plain copy print ?
  1. def insort_right(a, x, lo=0, hi=None):  
  2.     """Insert item x in list a, and keep it sorted assuming a is sorted. 
  3.  
  4.     If x is already in a, insert it to the right of the rightmost x. 
  5.  
  6.     Optional args lo (default 0) and hi (default len(a)) bound the 
  7.     slice of a to be searched. 
  8.     """  
  9.   
  10.     if lo < 0:  
  11.         raise ValueError('lo must be non-negative')  
  12.     if hi is None:  
  13.         hi = len(a)  
  14.     while lo < hi:  
  15.         mid = (lo+hi)//2  
  16.         if x < a[mid]: hi = mid  
  17.         else: lo = mid+1  
  18.     a.insert(lo, x)  
  19.   
  20. insort = insort_right   
具体我不知道Python的list是怎么个机制来平移的,但怎么平移又要保证大小的顺序不变,那么复杂度也是O(n)吧。


再次,当我们需要pop出一个元素的时候同样他的方法是直接用list.pop(item),这样也需要list自己来平移元素位置,复杂度也是O(n)


而实际上C++ STL中的优先队列的插入和删除的复杂度是O(logn)


对于Python list的机制我不了解,如果和C++中的数组平移是一样的话,那么这种优先队列的方法是不可取的。


那么就需要自己写堆了,说白了就是堆的Insert和Adjust两个函数就搞定了

需要说明的是:此代码中我没有使用list[0]这个位置,这样再写代码的时候比较直观,我是这样认为的,大家可以把root=0和root=1的两种堆画一画就知道我说的了(子节点)

[python]  view plain copy print ?
  1. #-*-coding:utf-8-*-  
  2. """ 
  3. class PriorityQueue: 
  4. """  
  5.   
  6. class PriorityQueue:  
  7.     def __init__(self):  
  8.         self.queue = []  
  9.         self.length = 0  
  10.         self.queue.insert(0self.length)  
  11.       
  12.     #队列中元素的个数  
  13.     def count(self):  
  14.         return self.length  
  15.       
  16.     #判断队列是否为空  
  17.     def empty(self):  
  18.         if self.count() == 0:  
  19.             return True  
  20.         else :  
  21.             return False  
  22.       
  23.     #取队列首元素,但是此时没有删除该元素  
  24.     def top(self):  
  25.         return self.queue[1]  
  26.       
  27.     #删除队首元素  
  28.     def pop(self):  
  29.         bEmpty = self.empty()  
  30.         if bEmpty == False:  
  31.             self.queue[1] = self.queue[self.length]  
  32.             self.length -= 1  
  33.             self._adjust()  
  34.       
  35.     #插入一个元素  
  36.     def push(self,item):  
  37.         self.length += 1  
  38.         self.queue.insert(self.length, item)  
  39.           
  40.         #插入元素后对堆进行调整,使其满足最大顶堆的性质  
  41.         i = self.length  
  42.         while i >= 2 and self.queue[i][1] > self.queue[i/2][1]:  
  43.             self.queue[i] , self.queue[i/2] = self.queue[i/2] , self.queue[i]  
  44.             i = i / 2  
  45.       
  46.     #堆的调整函数  
  47.     def _adjust(self):  
  48.         root = 1  
  49.         j = root << 1  
  50.         temp = self.queue[root]  
  51.         while j <= self.length:  
  52.             if j < self.length and self.queue[j][1] < self.queue[j+1][1]:  
  53.                 j += 1  
  54.             if self.queue[j] <= temp:  
  55.                 break  
  56.             self.queue[j],self.queue[root] = self.queue[root],self.queue[j]  
  57.             root = j  
  58.             j = j << 1  
  59.               
  60.         self.queue[root] = temp  
  61.           
  62. if __name__ == '__main__':  
  63.     pq = PriorityQueue()  
  64.     pq.push(15)  
  65.     pq.push(8)  
  66.     pq.push(9)  
  67.     pq.push(3)  
  68.     pq.push(7)  
  69.     pq.push(6)  
  70.     print pq.queue    
  71.     while pq.empty() == False:  
  72.         print "Value = ",pq.top()  
  73.         print pq.queue,pq.length  
  74.         pq.pop()  

代码我自己验证过了,应该是没有问题的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值