主要實現了四個函式:
add:往堆裡加新的值,相當於在list末尾新增值,然後siftup維護大根堆從上到下從大到小
class maxheap(object):
def __init__(self, maxsize):
self.maxsize = maxsize #堆的大小
self._elements = [0] * maxsize #初始化堆
self._count = 0 #索引
def add(self, value):
if self._count >= self.maxsize:
raise exception('full')
self._elements[self._count] = value #放到末尾
self._count += 1 #索引加一,這是當前的下乙個索引
self._siftup(self._count - 1) #siftup將當前索引值維護到堆的位置
def extract(self):
if self._count <= 0:
raise exception('empty')
value = self._elements[0] #記錄堆頂值
self._count-=1
self._elements[0] = self._elements[self._count] #末尾移到堆頂
self._siftdown(0) #從上到下維護堆
return value
def _siftup(self, index):
if index > 0:
parent = (index - 1) // 2 #當前索引的父索引
if self._elements[index] > self._elements[parent]: #當前值大於父,需要替換
self._elements[index], self._elements[parent] = self._elements[parent], self._elements[index]
self._siftup(parent) #加入的值換到了父索引位置,繼續向上看是不是比上一層的父更大
def _siftdown(self, index):
left = index * 2 + 1 #左子樹索引
right = index * 2 + 2 #右子樹索引
new_index = index #用乙個新索引,後面觀察需不需要換
if right < self._count: #有左右子樹的情況
if self._elements[left] <= self._elements[index] and self._elements[right] <= self._elements[index]: #當前比左右都大,不用操作
pass
else:
if self._elements[left] >= self._elements[right]:
new_index = left #左邊更大,且左邊大於當前,準備用左邊跟當前索引換
else:
new_index = right
elif left < self._count: #只有左子樹
if self._elements[left] >= self._elements[index]:
new_index = left
if new_index != index: #需要換
self._elements[new_index], self._elements[index] = self._elements[index], self._elements[new_index]
self._siftdown(new_index)
topk測試:
#測試**
import random
seq = list(range(10))
random.shuffle(seq)
heap = maxheap(len(seq))
for i in seq:
heap.add(i)
res =
for i in range(10):
heaqp用法:(heapq實現的是小根堆,用大根堆需要轉換成相反數)
將值item插入堆,並執行sift-up維持堆特性(列表末尾元素按規則向上移動)
將堆頂元素彈出,並執行sift-down位置堆特性(列表末尾元素賦值給list[0],並按規則向下移動)
4. heapq.heapreplace(heap, item)
和3的順序相反,先pop堆頂元素,然後push item入堆
5. heapq.heapify(x)
將列表x轉換為heap物件(inplace,線性時間)
6. heapq.merge(*iterables, key=none, reverse=false)
返回: 乙個iterable可迭代物件
操作: 將可迭代物件列表*iterables合併, 相當於對乙個大檔案分解的多個小檔案組合排序(具體原理見下方的磁碟排序)
引數: iterables: 多個輸入物件(已經從小到大排序), 例如多個已排序的小檔案
key: 用於比較大小的關鍵字字段, 預設為none
reverse: 預設輸出是從小到大, 設定為true後逆序輸出
7. heapq.nlargest(n, iterable, key=none)
返回乙個列表, 為根據key作為篩選條件從可迭代物件iterable中篩選的最大的n個元素
8. heapq.nsmallest(n, iterable, key=none)
返回乙個列表, 為根據key作為篩選條件從可迭代物件iterable中篩選的最小的n個元素
大根堆實現
堆 有兩種,一種是大根堆,另一種是小根堆。大根堆的意思是在跟的位置那個數是最大的。同理,小根堆的根元素是最小的。堆是乙個滿的二叉樹,除了最後乙個節點可能不是滿的。所以用陣列去陣列去實現它。乙個節點的index為i,則這個節點的兩個子節點的下標應該為2 i 1和2 i 2 父結點那就是 i 1 2 下...
C 實現大根堆
一 堆的定義 堆的物理儲存結構是一維陣列,邏輯儲存結構是完全二叉樹。堆的基本操作包括 insert 向堆中插入乙個元素,deletetop 刪除堆頂元素 上面的就是乙個大根堆,大根堆具有以下性質 每乙個節點的值都小於它父節點的值。我們也可以從上面的中看出來。但是需要注意的是,每乙個節點的值的大小與它...
堆(大根堆 小根堆)
堆又可稱之為完全二叉堆。這是乙個邏輯上基於完全二叉樹 物理上一般基於線性資料結構 如陣列 向量 鍊錶等 的一種資料結構。學習過完全二叉樹的同學們都應該了解,完全二叉樹在物理上可以用線性資料結構進行表示 或者儲存 例如陣列int a 5 就可以用來描述乙個擁有5個結點的完全二叉樹。那麼基於完全二叉樹的...