Python小根堆的實現

2021-10-20 13:28:13 字數 2869 閱讀 9126

實現堆的函式,像heapq的庫一樣,對列表進行操作。(小根堆

陣列中,根節點索引為0.

索引為idx

idxid

x的節點,左子節點為2∗i

dx+1

2 * idx + 1

2∗idx+

1,右子節點為2∗i

dx+2

2 * idx + 2

2∗idx+

2. 反過來,乙個節點下標為idx

idxid

x,它的父節點下標為(id

x−1)

//

2(idx - 1) // 2

(idx−1

)//2

.例如,索引為2的節點,左子節點和右子節點的索引分別為5和6.

實現堆,最關鍵的是對元素的移動(上移/下移)。所有函式都是基於這兩種操作完成的。

down指的是從堆底到堆頂的過程,指的是元素的索引小了,down了。反過來,up就是堆頂到堆底的過程,索引大了,up了。

_siftdown函式:將元素向堆頂移動到符合條件為止

'''將idx索引位置的元素往堆頂移動。startidx指堆頂的索引'''

def_siftdown

(heap, startidx, idx)

: newitem = heap[idx]

#先儲存下

'''逐步與父節點比'''

while startidx < idx:

parentidx =

(idx -1)

>>1#

parent = heap[parentidx]

'''這個元素比父節點小,就把父節點往下躥乙個'''

if newitem < parent:

heap[idx]

= parent #parent值向堆底移動

idx = parentidx

else

:break

'''while迴圈結束後,idx就處在上乙個父節點往下躥之後空出來的位置,把之前儲存的填進去就完成了'''

heap[idx]

= newitem

!!!重點,_siftup雖然將元素向堆底移動了,但是如果只移動的話,不一定符合堆的性質。所以_siftup函式要包含_siftdown函式,利用_siftdown函式再將元素向堆頂移動,找到其合適的位置。

這段**的最後一句注釋要仔細看

'''idx位置的元素往堆底移動'''

def_siftup

(heap, idx)

: endidx =

len(heap)-1

startidx = idx

newitem = heap[idx]

'''先儲存下,再把子節點往上提'''

child_idx =

2* idx +

1#初始為左子節點

while child_idx <= endidx:

'''共有兩個子節點,應該選較小的往上提'''

rightchild_idx = child_idx +

1if rightchild_idx <= endidx and heap[rightchild_idx]

<= heap[child_idx]

: child_idx = rightchild_idx

heap[idx]

= heap[child_idx]

idx = child_idx

child_idx =

2* idx +

1'''while結束時,idx停在最後乙個子節點向上躥,空出來的位置'''

heap[idx]

= newitem

'''前面節點往上躥的時候,newitem從來都沒和任何元素比較過,最後需要再嘗試把它往堆頂移,幫它找到正確的位置'''

_siftdown(heap, startidx, idx)

過程:把所有非葉子節點,逐個_siftup

def

heapify

(heap)

: n =

len(heap)

''' 二叉樹最後乙個的節點,在陣列中的下標為n - 1,它的父節點,也是二叉樹按順序的最後乙個父節點,

下標就是n - 2 // 2, 即n // 2 - 1

要從後往前,逐個處理

'''for i in

range

(n //2-

1,-1

,-1)

: _siftup(heap, i)

過程:將新元素新增到最末尾,再向堆頂移動該元素。

def

(heap, x)

: _siftdown(heap,0,

len(heap)-1

)

過程:思想是將堆頂元素heap[0]取出,再將堆末尾元素補到堆頂,再將這個元素_siftup。實現起來,先利用列表的pop函式獲得最後乙個元素,再將heap[0]作為返回值暫時儲存下來,再將最後乙個元素覆蓋到heap[0],再_siftup.

def

(heap)

: last = heap.pop(

)#heap為空直接報錯

'''先pop後,heap可能變成空了

如果不空,就將heap[0]作為返回值

若是空了,那就last直接就是返回值了

'''if heap:

ans = heap[0]

heap[0]

= last

_siftup(heap,0)

return ans

return last

小根堆 陣列實現

特點 父節點永遠比孩子節點小,不強制要求左孩子比右孩子小,但是為了實現方便,我令其左孩子比右孩子小。反之為大根堆。push 插入元素 陣列長度增加 注意 增加的不是本次插入所需要的位置,而是下次元素的位置,這句話能解釋為什麼pop的時候需要 se才能拿到當前堆中的最後乙個元素 從下往上判斷是否滿足小...

堆(大根堆 小根堆)

堆又可稱之為完全二叉堆。這是乙個邏輯上基於完全二叉樹 物理上一般基於線性資料結構 如陣列 向量 鍊錶等 的一種資料結構。學習過完全二叉樹的同學們都應該了解,完全二叉樹在物理上可以用線性資料結構進行表示 或者儲存 例如陣列int a 5 就可以用來描述乙個擁有5個結點的完全二叉樹。那麼基於完全二叉樹的...

堆(Heap)大根堆 小根堆

具有以下的特點 1 完全二叉樹 2 heap中儲存的值是偏序 min heap 父節點的值小於或等於子節點的值 max heap 父節點的值大於或等於子節點的值 一般都用陣列來表示堆,i結點的父結點下標就為 i 1 2。它的左右子結點下標分別為2 i 1和2 i 2。如第0個結點左右子結點下標分別為...