Python有队列类Queue,为啥就不提供个PriorityQueue类呢?
写优先队列也是在写爬虫的时候想到的,当时没想用PageRank算法(最终也没用),就直接用优先队列来放URL,但是发现Python没有优先队列。
网上我看到一哥们用Python的bisect包来实现优先队列的
具体的网址:http://www.kgblog.net/2009/04/25/pythonSpider.html
我们就来分析下他的优先队列算法复杂度吧,这仅仅是学术探讨,没有任何别的意思。
首先在元素插入队列的时候,bisect的原理是用二分来搜索需要插入的位置,然后将后面的元素平移一个位置,将该位置空出来给需要插入的元素
看bisect包的源码:
def insort_right(a, x, lo=0, hi=None): """Insert item x in list a, and keep it sorted assuming a is sorted. If x is already in a, insert it to the right of the rightmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo < 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo < hi: mid = (lo+hi)//2 if x < a[mid]: hi = mid else: lo = mid+1 a.insert(lo, x) 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的两种堆画一画就知道我说的了(子节点)
#-*-coding:utf-8-*- """ class PriorityQueue: """ class PriorityQueue: def __init__(self): self.queue = [] self.length = 0 self.queue.insert(0, self.length) #队列中元素的个数 def count(self): return self.length #判断队列是否为空 def empty(self): if self.count() == 0: return True else : return False #取队列首元素,但是此时没有删除该元素 def top(self): return self.queue[1] #删除队首元素 def pop(self): bEmpty = self.empty() if bEmpty == False: self.queue[1] = self.queue[self.length] self.length -= 1 self._adjust() #插入一个元素 def push(self,item): self.length += 1 self.queue.insert(self.length, item) #插入元素后对堆进行调整,使其满足最大顶堆的性质 i = self.length while i >= 2 and self.queue[i][1] > self.queue[i/2][1]: self.queue[i] , self.queue[i/2] = self.queue[i/2] , self.queue[i] i = i / 2 #堆的调整函数 def _adjust(self): root = 1 j = root << 1 temp = self.queue[root] while j <= self.length: if j < self.length and self.queue[j][1] < self.queue[j+1][1]: j += 1 if self.queue[j] <= temp: break self.queue[j],self.queue[root] = self.queue[root],self.queue[j] root = j j = j << 1 self.queue[root] = temp if __name__ == '__main__': pq = PriorityQueue() pq.push(15) pq.push(8) pq.push(9) pq.push(3) pq.push(7) pq.push(6) print pq.queue while pq.empty() == False: print "Value = ",pq.top() print pq.queue,pq.length pq.pop()
代码我自己验证过了,应该是没有问题的