資料結構堆(heap)是一種優先佇列。佇列是一種先進先出的資料結構。佇列的乙個重要變種稱為優先順序佇列。使用優先佇列能夠以任意順序增加物件,並且能在任意的時間(可能在增加物件的同時)找到(也可能移除)最小的元素,也就是說它比python的min方法更加有效率。
在優先順序佇列中,佇列中的項的邏輯順序由它們的優先順序確定。最高優先順序項在佇列的前面,最低優先順序的項在後面。因此,當你將項排入優先順序佇列時,新項可能會一直移動到前面。
我們的二叉堆實現的基本操作如下:
binaryheap() 建立乙個新的,空的二叉堆。注意,無論我們向堆中新增項的順序是什麼,每次都刪除最小的。insert(k) 向堆新增乙個新項。
findmin()返回具有最小鍵值的項,並將項留在堆中。
delmin() 返回具有最小鍵值的項,從堆中刪除該項。
如果堆是空的,isempty() 返回true,否則返回 false。
size() 返回堆中的項數。
buildheap(list) 從鍵列表構建乙個新的堆。
為了使我們的堆有效地工作,我們將利用二叉樹的對數性質來表示我們的堆。為了保證對數效能,我們必須保持樹平衡。平衡二叉樹在根的左和右子樹中具有大致相同數量的節點,它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。 在我們的堆實現中,我們通過建立乙個完整二叉樹來保持樹平衡。 乙個完整的二叉樹是乙個樹,其中 每層結點都完全填滿,在最後一層上如果不是滿的,則只缺少右邊的若干結點。 figure 1 展示了完整二叉樹的示例。
完整二叉樹的另乙個有趣的屬性是,我們可以使用單個列表來表示它。
# from pythonds.trees.binheap import binheap
class binheap:
def __init__(self):
self.heaplist = [0]
self.currentsize = 0
def insert(self,k):
'''將項附加到列表的末尾,並通過比較新新增的項與其父項,我們可以重新獲得堆結構屬性。 '''
self.currentsize = self.currentsize + 1
self.percup(self.currentsize)
def buildheap(self, alist):
'''直接將整個列表生成堆,將總開銷控制在o(n)'''
i = len(alist) // 2
self.currentsize = len(alist)
self.heaplist = [0] + alist[:] # 分片法[:]建立乙個列表的副本
while (i > 0):
self.percdown(i)
i = i - 1
def percup(self,i):
'''如果新新增的項小於其父項,則我們可以將項與其父項交換。'''
while i // 2 > 0: # // 取整除 - 返回商的整數部分(向下取整)
if self.heaplist[i] < self.heaplist[i//2]:
tmp = self.heaplist[i // 2]
self.heaplist[i // 2] = self.heaplist[i]
self.heaplist[i] = tmp
i = i // 2
def percdown(self, i):
'''將新的根節點沿著一條路徑「下沉」,直到比兩個子節點都小。'''
while (i * 2) <= self.currentsize:
mc = self.minchild(i)
if self.heaplist[i] > self.heaplist[mc]:
tmp = self.heaplist[i]
self.heaplist[i] = self.heaplist[mc]
self.heaplist[mc] = tmp
i = mc
def minchild(self, i):
'''在選擇下沉路徑時,如果新根節點比子節點大,那麼選擇較小的子節點與之交換。'''
if i * 2 + 1 > self.currentsize:
return i * 2
else:
if self.heaplist[i * 2] < self.heaplist[i * 2 + 1]:
return i * 2
else:
return i * 2 + 1
def delmin(self):
'''移走根節點的元素(最小項)後如何保持堆結構和堆次序'''
retval = self.heaplist[1]
self.heaplist[1] = self.heaplist[self.currentsize]
self.currentsize = self.currentsize - 1
self.heaplist.pop()
self.percdown(1)
return retval
bh = binheap()
bh.buildheap([9,5,6,2,3])
print(bh.delmin())
print(bh.delmin())
print(bh.delmin())
print(bh.delmin())
print(bh.delmin())
關於二叉堆的最後一部分便是找到從無序列表生成乙個「堆」的方法。我們首先想到的是,將無序列表中的每個元素依次插入到堆中。對於乙個排好序的列表,我們可以用二分搜尋找到合適的位置,然後在下乙個位置插入這個鍵值到堆中,時間複雜度為o(logn)。另外插入乙個元素到列表中需要將列表的一些其他元素移動,為新節點騰出位置,時間複雜度為o(n)。因此用insert方法的總開銷是o(nlogn)。其實我們能直接將整個列表生成堆,將總開銷控制在o(n)。listing 6 所示的是生成堆的操作。
能在o(n)的開銷下能生成二叉堆看起來有點不可思議,這裡就不做證明了。但要理解用o(n)的開銷能生成堆的關鍵是因為logn因子基於樹的高度。而對於buildheap裡的許多操作,樹的高度比logn要小。
參考:
資料結構 二叉堆
二叉堆一般用來實現優先佇列 優先佇列是一種至少允許以下兩種操作的資料結構 insert 以及 deletemin 同查詢樹一樣,二叉堆具有結構性與堆序性,對二叉堆的基本操作可能會破壞這些性質,所以二叉堆的操作要直到其基本性質滿足才能結束。一 結構性 二叉堆在結構上為完全二叉樹,其具有完全二叉樹的結構...
資料結構 二叉堆
二叉堆 優先佇列 具有結構性和堆序性 結構性為 二叉堆是一棵完全被填滿的二叉樹,有可能的例外是在底層,底層上的元素從左到右填入。這樣的樹稱為完全二叉樹。二叉堆可以用陣列表示,對於陣列中任意位置i上的元素,其左兒子在位置2i上,右兒子在位置2i 1上,父親則在i 2上 小於i 2的最小整數 堆序性為 ...
資料結構 二叉堆
二叉堆其實就是二叉樹,只不過二叉堆的最頂端的值,要麼最大,要麼最小,這要根據題意來定。如圖 讀者注意一下,圖上的黑字代表二叉堆的值,而紅色則代表下表。二叉堆的基本操作 插入,刪除和查詢。堆的stl實現 本人不太懂,就參考這位大佬的 上圖中,q.top 就是查詢,q.pop 就是刪除,q.push 就...