基于list实现的优先队列
class PrioQueueError(ValueError):
pass
class PrioQue:
def __init__(self, elist=[]):
self._elems = list(elist) # 1.对实参表做拷贝,避免共享。2.使构造函数的实参可以使任何可迭代对象。
self._elems.sort(reverse=True) # 较小作为优先级
def enqueue(self, e):
'''
while的条件循环保证优先度相同元素的正确排序顺序,
使同优先级的元素能先进先出
'''
i = len(self._elems) - 1
while i >= 0:
if self._elems[i] <= e:
i -= e
else:
break
self._elems.insert(i+1, e)
def is_empty(self):
return not self._elems
def peek(self):
if self.is_empty():
raise PrioQueueError("in top")
return self._elems[-1]
def dequeue(self):
if self.is_empty():
raise PrioQueueError("in top")
return self._elems.pop()
优先队列的堆实现
'''
插入元素:O(logn)
把新加入元素放在已有元素之后,执行一次向上筛选操作
向上筛选操作中比较和交换次数不会超过二叉树中最长路径,
弹出元素:O(logn)
弹出当时的堆顶
从堆最后去一个元素作为完全二叉树
执行一次向下筛选
'''
class PrioQueue:
""" Implementing priority queues using heaps
"""
def __init__(self, elist=[]):
self._elems = list(elist)
if elist:
self.buildheap()
def is_empty(self):
return not self._elems
def peek(self):
if self.is_empty():
raise PrioQueueError("in peek")
return self._elems[0]
def enqueue(self, e):
self._elems.append(None) # add a dummy element
self.siftup(e, len(self._elems)-1)
def siftup(self, e, last):
elems, i, j = self._elems, last, (last-1)//2
while i > 0 and e < elems[j]:
elems[i] = elems[j]
i, j = j, (j-1)//2
elems[i] = e
def dequeue(self):
if self.is_empty():
raise PrioQueueError("in dequeue")
elems = self._elems
e0 = elems[0]
e = elems.pop()
if len(eles) > 0:
self.siftdowm(e, 0, len(elems))
return e0
def siftdowm(self, e, beign, end):
elems, i, j = self._elems, begin, begin*2 + 1
while j < end: # invariant: j == 2*i+1
if j+1 < end and elems[j+1] < elems[j]:
j += 1 # elems[j]不大于其兄弟节点的数据
if e < elems[j]: # e在三者中最小,已找到了位置
break
elems[i] = elems[j] # elems{j}在三者中最小,上移
i, j = j, 2*j+1
elems[i] = e
def buildheap(self):
end = len(self._elems)
for i in range(end//2, -1, -1):
self.siftdowm(self._elems[i], i, end)
堆的应用:堆排序
def head_sort(elems):
def siftdowm(elems, e, begin, end):
i, j = beign, begin*2+1
while j < end: # invariant: j == 2*i+1
if j+1 < end and elems[j+1] < elems[j]:
j += 1 # elems[j]不大于其兄弟节点的数据
if e < elems[j]: # e在三者中最小,已找到了位置
break
elems[i] = elems[j] # elems{j}在三者中最小,上移
i, j = j, 2*j+1
elems[i] = e
end = len(elems)
for i in range(end//2, -1, -1):
siftdowm(elems, elems[i], i, end)
for i in range((end-1), 0, -1):
e = elems[i]
elems[i] = elems[0]
siftdowm(elems, e, 0, i)