python資料結構 二叉堆

2021-08-29 20:56:21 字數 3175 閱讀 1546

資料結構堆(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 就...