堆实现
#------------------------------------------------------------------------------
#堆Heap
#------------------------------------------------------------------------------
import sys
class Heap():
def __init__(self, A: list):
self.A = A
self.heap_size = len(A)
#返回父节点索引
def parent(self, i: int) -> int:
return int((i-1)/2)
#返回左孩子索引
def left(self, i: int) -> int:
return 2*i + 1
#返回右孩子索引
def right(self, i: int) -> int:
return 2*i + 2
#维护最大堆性质
def max_heapify(self, i):
l = self.left(i)
r = self.right(i)
if l < self.heap_size and self.A[l] > self.A[i]:
largest = l
else:
largest = i
if r < self.heap_size and self.A[r] > self.A[largest]:
largest = r
if largest != i:
self.A[i], self.A[largest] = self.A[largest], self.A[i]
self.max_heapify(largest)
#维护最小堆性质
def min_heapify(self, i):
l = self.left(i)
r = self.right(i)
if l < self.heap_size and self.A[l] < self.A[i]:
smallest = l
else:
smallest = i
if r < self.heap_size and self.A[r] < self.A[smallest]:
smallest = r
if smallest != i:
self.A[i], self.A[smallest] = self.A[smallest], self.A[i]
self.min_heapify(smallest)
#创建最大堆
def build_max_heap(self):
#不除以2也可以,为减少计算量
for i in range(int(len(self.A)/2)-1, -1, -1):
self.max_heapify(i)
#创建最小堆
def build_min_heap(self):
for i in range(int(len(self.A)/2)-1, -1, -1):
self.min_heapify(i)
#堆排序(升序)
def heap_sort(self):
self.build_max_heap()
for i in range(len(self.A)-1, 0 ,-1):
self.A[0], self.A[i] = self.A[i], self.A[0]
self.heap_size -= 1
self.max_heapify(0)
# =============================================================================
# A = [4,1,3,2,16,9,10,14,8,7]
# heap = Heap(A)
# heap.heap_sort()
# =============================================================================
最大优先队列
''''最大优先队列'''
class HeapMaxPriorityQueue():
def __init__(self, A):
self.A = A
self.heap = Heap(A)
#创建最大堆
self.heap.build_max_heap()
#返回A中具有最大键字的元素
def heap_maximun(self):
return A[0]
#去掉并返回A中具有最大键字的元素
def heap_extract_max(self):
if self.heap.heap_size < 1:
sys.exit('heap underflow')
Max = self.A[0]
self.A[0] = self.A[self.heap.heap_size - 1]
self.heap.heap_size -= 1
self.A.pop()
self.heap.max_heapify(0)
return Max
#将元素i的值增加到k
def heap_increase_key(self, i, key):
if key < self.A[i]:
sys.exit('new key is smaller than current key!!!')
self.A[i] = key
while i > 0 and self.A[self.heap.parent(i)] < A[i]:
self.A[i], self.A[self.heap.parent(i)] = \
self.A[self.heap.parent(i)],self.A[i]
i = self.heap.parent(i)
#插入新元素
def heap_max_insert(self, key):
self.heap.heap_size += 1
self.A.append(-float('inf'))
#将末尾元素键值增加到key
self.heap_increase_key(self.heap.heap_size - 1, key)
# =============================================================================
# A = [4,1,3,2,16,9,10,14,8,7]
# MaxPriorityQueue = HeapMaxPriorityQueue(A)
# print(MaxPriorityQueue.heap_extract_max() )
# # MaxPriorityQueue.heap_max_insert(13)
# =============================================================================
最小优先队列
''''最小优先队列'''
class HeapMinPriorityQueue():
def __init__(self, A):
self.A = A
self.heap = Heap(A)
#创建最小堆
self.heap.build_min_heap()
#返回A中具有最大键字的元素
def heap_minimun(self):
return A[0]
#去掉并返回A中具有最大键字的元素
def heap_extract_min(self):
if self.heap.heap_size < 1:
sys.exit('heap underflow')
Min = self.A[0]
self.A[0] = self.A[self.heap.heap_size - 1]
self.heap.heap_size -= 1
self.A.pop()
self.heap.min_heapify(0)
return Min
#将元素i的值减小到k
def heap_increase_key(self, i, key):
if key > self.A[i]:
sys.exit('new key is bigger than current key!!!')
self.A[i] = key
while i > 0 and self.A[self.heap.parent(i)] > A[i]:
self.A[i], self.A[self.heap.parent(i)] = \
self.A[self.heap.parent(i)],self.A[i]
i = self.heap.parent(i)
#插入新元素
def heap_min_insert(self, key):
self.heap.heap_size += 1
self.A.append(float('inf'))
#将末尾元素键值增加到key
self.heap_increase_key(self.heap.heap_size - 1, key)
最小优先队列可以使用Python自带的'heapq'完成
import heapq
A = [4,1,3,2,16,9,10,14,8,7]
heapq.heapify(A)
heapq.heappop(A)
heapq.heappush(A, 0.4)
heapq模块提供了如下几个函数:
- heapq.heappush(heap, item) : 把item添加到heap中(heap是一个列表)
- heapq.heappop(heap) : 把堆顶元素弹出,返回的就是堆顶(优先级最高的元素)
- heapq.heappushpop(heap, item) :先把item加入到堆中,然后再pop,比heappush()再heappop()要快得多
- heapq.heapreplace(heap, item) :先pop,然后再把item加入到堆中,比heappop()再heappush()要快得多
- heapq.heapify(x) :将列表x进行堆调整,默认返回的是小顶堆
- heapq.merge(*iterables) :将多个列表合并,并进行堆调整,返回的是合并后的列表的迭代器
- heapq.nlargest(n, iterable, key=None) 返回最大的n个元素(Top-K问题)
- heapq.nsmallest(n, iterable, key=None) 返回最小的n个元素(Top-K问题)
note
- item可以为各种形式,比如可以为元组,这样在进行堆调整是,先以元组第一个元素为基准,如果第一个相等,再以第二个为基准,依次类推
- 使用堆操作,在一个有n个元素的堆中添加一个元素或者删除一个元素的时间复杂度均为O(logn)