資料結構與演算法(python) 優先佇列和二叉堆

2021-10-09 19:33:01 字數 3888 閱讀 4902

參考自 mooc資料結構與演算法python版

二、二叉堆的實現

佇列有一種變體稱為「優先佇列」,優先佇列的出隊跟佇列一樣從隊首出隊,但在優先佇列內部, 資料項的次序卻是由「優先順序」來確定:高優先順序的資料項排在隊首,而低優先順序的資料項則排在後面。這樣,優先佇列的入隊操作就比較複雜,需要將資料項根據其優先順序盡量擠到佇列前方。

有什麼方案可以用來實現優先佇列?

二叉堆能夠將優先佇列的入隊出隊複雜度都保持在o(l

ogn)

o(log n)

o(logn

)。二叉堆的有趣之處在於, 其邏輯結構上像二叉樹, 卻是用非巢狀的列表來實現的

adt binaryheap的操作定義如下:

函式含義

binaryheap()

建立乙個空二叉堆物件

insert(k)

將新key加入到堆中

findmin()

返回堆中的最小項,最小項仍保留在堆中

delmin()

返回堆中的最小項,同時從堆中刪除

isempty()

返回堆是否為空

size()

返回堆中key的個數

buildheap(list)

從乙個key列表建立新堆

【**】:

from pythonds.trees.binheap import binheap

bh = binheap(

)bh.insert(5)

bh.insert(7)

bh.insert(3)

bh.insert(11)

print

(bh.delmin())

print

(bh.delmin())

print

(bh.delmin())

print

(bh.delmin(

))

為了使堆操作能保持在對數水平上, 就必須採用二叉樹結構;

同樣, 如果要使操作始終保持在對數數量級上, 就必須始終保持二叉樹的「平衡」

– 樹根左右子樹擁有相同數量的節點

我們採用「完全二叉樹」的結構來近似實現「平衡」

葉節點最多隻出現在最底層和次底層,而且最底層的葉節點都連續集中在最左邊,每個內部節點都有兩個子節點, 最多只有1個節點例外,比如下圖中的18號節點。

如果節點的下標為p,那麼其左子節點下標為2p,右子節點為2p+1,其父節點下標為p//2

堆的性質:在任何一條路徑上,它都是乙個有序的佇列。

採用乙個列表來儲存堆資料,其中表首下標為0的項無用,但為了後面**可以用到簡單的整數乘除法,仍保留它。

class

binheap

:def

__init__

(self)

: self.heaplist =[0

] self.currentsize =

0

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#再往上一級

definsert

(self,k)

:#新增到末尾

self.currentsize = self.currentsize +

1#size+1

self.percup(self.currentsize)

# 上浮,比較大小

移走根節點heaplist[1],並保證堆次序不被破壞。

先用最後乙個節點來代替根節點,再將新的根節點沿著一條路徑「下沉」,直到比兩個子節點都小

「下沉」路徑的選擇:如果比子節點大,那麼選擇兩個子節點中較小的子節點交換下沉。示 意圖如下:

左子節點9,右子節點 11,27和9交換。

左子節點14,右子節點 18,27和14交換。

左子節點33,右子節點 17,27和17交換。

#找出較小的子節點

if self.heaplist[i]

> self.heaplist[mc]

:#如果大於子節點,交換下沉

tmp = self.heaplist[i]

self.heaplist[i]

= self.heaplist[mc]

self.heaplist[mc]

= tmp

i = mc #沿路徑向下

defminchild

(self, i)

:#找出較小的子節點

if i *2+

1> self.currentsize:

return i*

2else

:if self.heaplist[i*2]

< self.heplist[i*2+

1]:return i*

2else

:return i*2+

1def

delmin

(self)

: retval = self.heaplist[1]

#移走堆頂

self.heaplist[1]

= self.heaplist[self.currensize]

self.currentsize -=

1 self.heaplist.pop(

) self.percdown(1)

#新頂下沉

return retval

下沉法,能夠將總代價控制在o(n

)o(n)

o(n)

【**】:

def

buildheap

(self, alist)

: i =

len(alist)//2

#從最後節點的父節點開始

self.currentsize =

len(alist)

self.heaplist =[0

]+ alist[:]

print

(len

(self.heaplist)

,i)while

(i>0)

:print

(self.heaplist, i)

self.percdown(i)

i -=

1print

(self.heaplist, i)

資料結構與演算法 優先佇列

優先佇列按照佇列的方式正常入隊,但按照優先順序出隊。有兩種實現方式 堆 二插堆 多項式堆等等 和二叉搜尋樹。這裡重點講解二叉堆,關於二叉搜尋樹的內容見這篇文章。堆是一種特殊的完全二叉樹。大根堆 完全二叉樹的任一節點都比其孩子節點大。小根堆 完全二叉樹的任一節點都比其孩子節點小。堆的向下調整 假設根節...

資料結構與演算法 優先佇列

英雄聯盟遊戲裡面防禦塔都有乙個自動攻擊功能,小兵排著隊進入防禦塔的攻擊範圍,防禦塔先攻擊靠得最近的小兵,這時候大炮車的優先順序更高 因為系統判定大炮車對於防禦塔的威脅更大 所以防禦塔會優先攻擊大炮車。而當大炮車陣亡,剩下的全部都是普通小兵,這時候離得近的優先順序越高,防禦塔優先攻擊距離更近的小兵。優...

python資料結構與演算法

coding utf 8 import sys 使用以下語句將引數的str格式轉換為int格式 l list map int sys.argv 1 split target int sys.argv 2 def binarysearch print l print target left 0 rig...