實現堆的函式,像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個結點左右子結點下標分別為...