Python算法详解
上QQ阅读APP看书,第一时间看更新

4.3.5 实践演练——基于堆实现的优先队列

下面的实例文件dui.py演示了基于堆实现优先队列的过程。

源码路径:daima\第4章\dui.py

class Heap_Pri_Queue(object):
     def __init__(self, elems = []):
          self._elems = list(elems)
          if self._elems:
                self.buildheap()
     #判断是否为空
     def is_empty(self):
          return self._elems is []
     #查看堆顶元素,即优先级最低的元素
     def peek(self):
          if self.is_empty():
                raise HeapPriQueueError("in pop")
          return self._elems[0]
     #将新的优先级加入队列O(log n)
     def enqueue(self, e):
          #在队列末尾创建一个空元素
          self._elems.append(None)
          self.siftup(e, len(self._elems) - 1)
     #新的优先级默认放在末尾,因此失去堆序,进行siftup,构建堆序
     #将e位移到正确的位置
     def siftup(self, e, last):
          elems, i, j = self._elems, last, (last-1)//2 #j为i的父节点
          while i>0 and e < elems[j]:
               elems[i] = elems[j]
               i, j = j, (j-1)//2
          elems[i] = e
    #堆顶值最小、优先级最高的出队,确保弹出元素后仍然维持堆序
    #将最后的元素放在堆顶,然后进行siftdown
    #  O(log2n)
    def dequeue(self):
         if self.is_empty():
              raise HeapPriQueueError("in pop")
         elems = self._elems
         e0 = elems[0]
         e = elems.pop()
         if len(elems)>0:
              self.siftdown(e, 0, len(elems))
         return e0
     def siftdown(self, e, begin, end):
         elems, i, j = self._elems, begin, begin*2 + 1
        while j < end:
             if j+1 < end and elems[j] > elems[j+1]:
                  j += 1
             if e < elems[j]:
                  break
             elems[i] = elems[j]
             i, j = j, j*2+1
        elems[i] = e
     #构建堆序O(n)
     def buildheap(self):
         end = len(self._elems)
        for i in range(end//2, -1, -1):
              self.siftdown(self._elems[i], i, end)
if __name__=="__main__":
     l = Heap_Pri_Queue([5,6,1,2,4,8,9,0,3,7])
     print(l._elems)
     #[0, 2, 1, 3, 4, 8, 9, 6, 5, 7]
     l.dequeue()
     print(l._elems)
     #[1, 2, 7, 3, 4, 8, 9, 6, 5]
     print(l.is_empty())
     l.enqueue(0)
     print(l._elems)
     print(l.peek())

执行后会输出:

[0, 2, 1, 3, 4, 8, 9, 6, 5, 7]
[1, 2, 7, 3, 4, 8, 9, 6, 5]
False
[0, 1, 7, 3, 2, 8, 9, 6, 5, 4]
0