heap介紹
binary heap可以被看成是一種接近完成的binary tree。可以分為max-heap和min-heap,max-heap的parent要比children大,min-heap相反。
通常用array A構成的heap中,有兩個基本的特性:1. A.length,給出了陣列中的元素個數。2. A.heap-size,給出陣列中在heap中的元素。
這兩者的區別是,A.heap-size中的才是在heap里的,A.length的長度可能還包含了其他的很多元素。
這個可以在之后的代碼中可以看見。比如有一個list有8個元素,但只有前7個元素在heap里,滿足heap的特性,則A.length=8, A.heap-size=7。
heap與array的示意圖如下。
一些特性:
-
對於每個節點,要想知道其父與子,有以下關系:
PARENT(i)
return[i/2]
LEFT(i)
return[2i]
RIGHT(i)
return(2i+1)
注意,這里的i是從1開始的,在實際寫代碼是,一般的list序列都是從0開始,要注意兩者之間的不同。這個在之后的代碼中會有體現。 -
要把一個A[1...n]轉化成heap,在A([n/2]+1...n)中的所有元素都是heap的葉子。
-
保持max-heap特性的操作

這個函數結合build Max heap 是保持整個heap特性的關鍵。下面討論具體的實現方法
創建一個max heap
首先要實現從某一個節點開始的max heap
算法如下:
此過程的時間復雜度為o(logn)
在此基礎上,建立一個max heap的算法如下:
此過程的時間復雜度為o(nlogn)
heap的priority-queue運算
prority-queue是一種數據結構,它的每一個元素都有一個key值,主要有以下幾種運算,其使用heap實現的算法如下。
插入一個元素
此過程的時間復雜度為o(logn)
增加一個元素的值
此過程的時間復雜度為o(logn)
提取最大元素
此過程的時間復雜度為o(logn)
從中可以看到heap的一個重要特性,就是它可以將所有priority-queue運算在時間復雜度lgn內完成。
heap的應用:heap sort
整個過程分為
- 建立heap
- 提取最大值
- 放在序列最后
- 重復指導排序完成
具體算法如下:
實現
#heap
class heap(object):
def __init__(self,A):
"""
A is a list
"""
# self.list = [0]
self.list = A[:]
# self.list.insert(0,0)
self.heapsize = len(A)
# self.ismaxheap = False
self.build_max_heap()
def __str__(self):
return str(self.list)
def left(self, i):
return 2*(i+1)-1
def right(self, i):
return 2*(i+1)
def parent(self, i):
return (i-1)/2
def insert(self, key):
"""
run time o(logn)
"""
self.heapsize += 1
self.list.append(-float("inf"))
self.increase_key(self.heapsize-1,key)
def increase_key(self,i,key):
"""
run time o(logn)
"""
if key < self.list[i]:
raise ValueError("new key is smaller than current key")
self.list[i] = key
while i>0 and self.list[self.parent(i)] < self.list[i]:
# print("i1="+str(i))
temp = self.list[i]
self.list[i] = self.list[self.parent(i)]
self.list[self.parent(i)] = temp
i = self.parent(i)
# print("i2="+str(i))
def max_heapify(self, i):
"""
run time: o(logn)
the key to maintain the max-heap property
"""
l = self.left(i)
r = self.right(i)
# i_m = i
# largest = 0
# print("l="+str(l)+" r="+str(r))
# print(self.heapsize)
largest = i
if l < self.heapsize:
if self.list[l] > self.list[i]:
largest = l
# print("r="+str(r)+" largest="+str(largest))
if r < self.heapsize:
if self.list[r] > self.list[largest]:
largest = r
# print("largest="+str(largest))
if largest != i:
temp = self.list[i]
self.list[i] = self.list[largest]
self.list[largest] = temp
self.max_heapify(largest)
def build_max_heap(self):
"""
run time: o(nlogn)
"""
# print(self.heapsize//2)
for i in range(self.heapsize//2-1,-1,-1):
# print(i)
self.max_heapify(i)
# self.ismaxheap = True
def extract_max(self):
"""
build a maxheap and return the max value of it(the first element)
also pop the first element out of the heap
run time o(logn)
"""
if self.heapsize < 1:
raise ValueError("heap underflow")
# if self.ismaxheap == False:
# self.build_max_heap()
maxele = self.list[0]
self.list[0] = self.list[self.heapsize-1]
self.list[self.heapsize-1] = maxele
self.heapsize -= 1
self.max_heapify(0)
return maxele
def heap_sort(self):
"""
using recurrence to impelete, can also use for loop
"""
if self.heapsize == 1:
return self.list
self.build_max_heap()
temp = self.list[0]
self.list[0] = self.list[self.heapsize-1]
self.list[self.heapsize-1] = temp
self.heapsize -= 1
self.heap_sort()
A = [3,4,5,7,1,4,9]
heap1 = heap(A)
print(heap1)
heap1.insert(2)
print(heap1)
print(heap1.heapsize)
maxele = heap1.extract_max()
print(maxele)
print(heap1)
print(heap1.heapsize)
heap1.increase_key(3,10)
print(heap1)
print(heap1.heapsize)
heap1.heap_sort()
print(heap1)
print(heap1.heapsize)