1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3
4 '''
5 Author: Minion-Xu
6 '''
7
8 #异常类
9 class HeapPriQueueError(ValueError):
10 pass
11
12 class Heap_Pri_Queue(object):
13 def __init__(self, elems = []):
14 self._elems = list(elems)
15 if self._elems:
16 self.buildheap()
17
18 #判断是否为空
19 def is_empty(self):
20 return self._elems is []
21
22 #查看堆顶元素,即优先级最低元素
23 def peek(self):
24 if self.is_empty():
25 raise HeapPriQueueError("in pop")
26 return self._elems[0]
27
28 #将新的优先级加入队列 O(logn)
29 def enqueue(self, e):
30 #在队列末尾创建一个空元素
31 self._elems.append(None)
32 self.siftup(e, len(self._elems) - 1)
33
34 #新的优先级默认放在末尾,因此失去堆序,进行siftup构建堆序
35 #将e位移到真确的位置
36 def siftup(self, e, last):
37 elems, i, j = self._elems, last, (last-1)//2 #j为i的父节点
38 while i>0 and e < elems[j]:
39 elems[i] = elems[j]
40 i, j = j, (j-1)//2
41 elems[i] = e
42
43 #堆顶值最小优先级最高的出队,确保弹出元素后任然维持堆序
44 #将最后的元素放在堆顶,然后进行siftdown
45 # O(logn)
46 def dequeue(self):
47 if self.is_empty():
48 raise HeapPriQueueError("in pop")
49 elems = self._elems
50 e0 = elems[0]
51 e = elems.pop()
52 if len(elems)>0:
53 self.siftdown(e, 0, len(elems))
54 return e0
55
56 def siftdown(self, e, begin, end):
57 elems, i, j = self._elems, begin, begin*2 + 1
58 while j < end:
59 if j+1 < end and elems[j] > elems[j+1]:
60 j += 1
61 if e < elems[j]:
62 break
63 elems[i] = elems[j]
64 i, j = j, j*2+1
65 elems[i] = e
66
67 #构建堆序 O(n)
68 def buildheap(self):
69 end = len(self._elems)
70 for i in range(end//2, -1, -1):
71 self.siftdown(self._elems[i], i, end)
72
73
74 if __name__=="__main__":
75 l = Heap_Pri_Queue([5,6,1,2,4,8,9,0,3,7])
76 print(l._elems)
77 #[0, 2, 1, 3, 4, 8, 9, 6, 5, 7]
78 l.dequeue()
79 print(l._elems)
80 #[1, 2, 7, 3, 4, 8, 9, 6, 5]
81 print(l.is_empty())
82 l.enqueue(0)
83 print(l._elems)
84 print(l.peek())
插入元素:末尾插入, 向上筛选(siftup)
弹出元素:堆顶弹出, 末尾元素充当堆顶, 向下筛选(siftdown)