簡單來講就是將陣列按照完全二叉樹的形式排列。葉節點的元素個數最多為2^(n-1)次方,其中n為堆高度。
最大堆:某一根葉節點的元素小於等於根節點的數值。通常用於排序
最小堆:某一根葉節點的元素大於等於根節點的數值。通常用於構造優先佇列
首先建立最大堆: 函式輸入引數為乙個序列和序列的某一下標。
對於某一下標,首先求出該節點下的左子樹和右子樹下標,左子樹和右子樹分別于父節點對比,大者的下標標記為largest,如果最大值的下標發生了改變(不等於i)交換兩者元素,繼續重新判斷子樹下面是否滿足最大堆條件
def max_heapify(a,i):
l=2*i+1 #子節點下標
r=2*(i+1)
if l<=len(a)-1 and a[l]>a[i]:
largest=l
else:
largest=i
if r<=len(a)-1 and a[r]>a[largest]:
largest=r
if largest !=i:
a[i],a[largest]=a[largest],a[i]
max_heapify(a,largest)
def build_max_heap(a):
for i in range((len(a)-1)//2,-1,-1):
max_heapify(a,i) #這裡是繼續判斷子樹下面的子樹是否也滿足最大堆條件
現在的重點是如何把堆上的元素取下來。注意到最大堆的根節點a[0]必定是最大值。通過把它與a[n-1]進行互換,然後去掉最大元素,再次呼叫max_heapify(a,0),實際上這個函式max_heapify(a,i)能選擇出下標比i大的元素中最大的那個元素作為根節點。重複呼叫上面的過程就能一步一步把最大的元素取出來。
a=[4,1,3,2,16,9,10,14,8,7]
def heapsort(a):
b=a.copy()
c=build_max_heap(b)
for i in range(len(a)-1,0,-1):
del b[0]
max_heapify(b,0)
return c
print( heapsort(a))
a=heapsort(a)
執行結果:[16, 14, 10, 9, 8, 7, 4, 3, 2, 1]
基於最大堆實現最大優先佇列:在共享計算機系統的作業排程中,最大優先佇列記錄將要執行的各個作業以及他們之間的相對優先順序。當乙個作業完成或者被中斷後,呼叫extract_max從所有的等待作業中,選出最高優先順序的作業來執行。在任何時候,排程器都可以呼叫insert把乙個作業加入到佇列中來。
主要實現以下功能:
insert(s,x):把元素x插入集合s中。
maximun(s):返回s中具有最大優先序號的元素。
extract_max(s):去掉並返回s中的具有最大優先序號的元素。
increase_key(s,x,k):將元素x的優先序號增加到k,這裡假設k的值不小於x的優先序號。
a=heapsort(a)
def heap_maximum(a):
return a[0]
def heap_rxtract_max(a):
if len(a)<1:
ex1=exception("heap underflow") #exception(*args)
raise ex1
max=a[0]
a=a[1:len(a)]
max_heapify(a,0)
return max,a
def heap_incease_key(a,i,key):
if key0 and a[(i-1)//2]輸出結果:
16(16, [14, 10, 9, 8, 7, 4, 3, 2, 1])
[16, 14, 10, 12, 8, 7, 4, 3, 2, 1]
這裡有一點需要注意的是:列表作為函式引數傳入時,對列表進行切片操作(這相當於是複製[:])時不會改變原來列表的值;但是在進行下標修改時,由於列表是可變引數,會改變原來列表的值。
這裡我們自定義個兩個異常,當發生特定條件是丟擲異常。
6.5-3 要求利用最小堆實現最小優先佇列
在最大堆的基礎上把大於小於號修改一下即可。
def min_heapify(a,i):
l=2*i+1 #子節點下標
r=2*(i+1)
if l<=len(a)-1 and a[l]a[i]:
ex2=exception('new key is biger current key')
raise ex2
a[i]=key
while i>0 and a[(i-1)//2]>a[i]:#父節點比a[i]大的話更新父節點,始終滿足最小堆性質
a[i],a[(i-1)//2]=a[(i-1)//2],a[i]
i=(i-1)//2
return a
def heap_insert(a,key):
heap_decease_key(a,len(a)-1,key)
print(heap_minimum(a))
print(heap_erxtract_min(a))
print(heap_decease_key(a,8,12))
6.5-8 實現將結點i從堆a中刪除。
將被刪除的結點換成inf無窮大,利用切片操作刪除inf元素,呼叫max_heapify使得滿足最大堆性質。
def heap_delete(a,i):
heap_decease_key(a,i,float('inf'))
a[0]=a[-1]
a=a[0:-1]
max_heapify(a,0)
return a
思考題6.1 用插入的方法建堆
因為在heap_insert函式呼叫了heap_increase_key函式,該函式使得序列始終滿足最大堆性質。因此可用插入法,每插入乙個元素就進行重新建堆操作,使得滿足最大堆性質。
def build_max_heap2(a):
b=for i in range(0,len(a)):
heap_insert(b,a[i])
return b
思考題2 對d叉堆的分析
def dmax_heapify(a,i,d):
l=for k in range(0,d):
if (d*i+k+1)<=len(a)-1: #如果索引不會大於a的索引,就可以往l中擴充套件元素
num=float('-inf')
flag=0
largest=i
for k in range(0,len(l)):
if a[l[k]]>num:
num=a[l[k]] #子節點中的最大值
flag=l[k] #子節點中的最大值的索引
if num>a[i]:
largest=flag
if largest !=i:
a[i],a[largest]=a[largest],a[i]
dmax_heapify(a,largest,d)
def build_dmax_heap(a,d):
for i in range((len(a)-1)//d,-1,-1):
dmax_heapify(a,i,d) #這裡是繼續判斷子樹下面的子樹是否也滿足最大堆條件
a=[0,1,2,3,4,5,63,7,8,9,10,11,12]
build_dmax_heap(a,3)
print(a)
def extract_dmax(a,d):
if len(a)<1:
ex1=exception("heap underflow") #exception(*args)
raise ex1
max=a[0]
a=a[1:len(a)]
dmax_heapify(a,0,d)
return max,a
def increase_key(a,i,k,d):
if k0 and a[(i-1)//d]輸出結果:[63, 5, 9, 12, 4, 0, 1, 7, 8, 2, 10, 11, 3]滿足3叉堆的性質。具體思路:首先建立了乙個序列用於儲存子節點的索引值,這裡進行了乙個判斷,如果算出來的子串行的索引值大於len(a)-1,就不對l序列進行擴充套件。然後找出子串行中最大的那個值,num儲存子節點中的最大值,flag儲存最大值的索引值,最後進行判斷,如果largest的值不等於i,說明父子結點進行了交換,保持最大堆性質,之後遞迴呼叫dmax_heapify函式,保證一開始的父節點(此時已經做過某一更高層數的父節點的子節點了)也滿足最大堆條件。build——dmax_heap函式用於對所有的非葉節點進行函式dmax_heapify呼叫。
6-3 young氏矩陣的構建以及實現查詢功能
楊氏矩陣,每一行元素的資料都是從左至右的排序,每一列資料都是從上至下的排序。可以存在一些值為無窮大的資料項,表示那些不存在的元素
# coding:utf-8
def build_tableau(arr):
max_number=float('inf')
import math
n=int(math.sqrt(len(arr)))
m=nif n**2target:
i-=1 #利用楊氏矩陣的性質,大小是從左至右和從上至下排列
else:
j+=1
return 'no such element'
print(tableau_search(build_tableau(a),8))
1.演算法導論 機械工業出版社 第六章 堆排序。 演算法導論 6 堆排序
堆的分類 最大堆性質 高度 對於堆的一些基本操作 偽 描述 實現 max heapify python實現 123 4567 891011 1213 def max heapify i print max heapify i l left i r right i if l heap size and...
《演算法導論》學習分享 6 堆排序
堆排序也是一種時間複雜度為o n lg n omicron n lg n o nlgn 的排序演算法,但是與歸併排序不同的是堆排序是一種原址排序,也就是說排序過程只是交換資料的位置。堆是乙個陣列,儲存乙個近似完全二叉樹,樹上的每個結點對應陣列中的乙個元素,陣列第乙個元素儲存根節點,第i個元素的左孩子...
演算法導論(6)
演算法最壞情況執行時間 平均情況 期望執行時間 插入排序 theta n 2 theta n 2 歸併排序 theta n lg n theta n lg n 堆排序 o n lg n 快速排序 theta n 2 theta n lg n 期望 計數排序 theta k n theta k n 基...