python資料結構_大頂堆和小頂堆
阿新 • • 發佈:2020-07-27
大頂堆和小頂堆
相關介紹可參看:北京大學空地學院資料結構與演算法 第六章 6.8.2.2 小節
程式碼實現如下
class Heap: """二叉堆的實現 小頂堆""" def __init__(self): self.heapList = [0] # 預設一個 0 做佔位,使得根節點的索引在 1 上 self.currentSize = 0 # 最大節點的索引位置 def perUp(self, i): """將小節點逐步上升""" while i // 2 > 0: if self.heapList[i] < self.heapList[i // 2]: self.heapList[i], self.heapList[i // 2] = self.heapList[i // 2], self.heapList[i] i = i // 2 def insert(self, k): """插入節點""" self.heapList.append(k) self.currentSize += 1 self.perUp(self.currentSize) 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 perDown(self, i): """將節點下沉到合適位置""" while (i * 2) <= self.currentSize: # 說明有子節點 mc = self.minChild(i) if self.heapList[i] > self.heapList[mc]: self.heapList[i], self.heapList[mc] = self.heapList[mc], self.heapList[i] i = mc def delMin(self): """刪除小節點""" retval = self.heapList[1] # 刪除索引位置為 1 的節點 self.heapList[1] = self.heapList[self.currentSize] self.heapList.pop() self.currentSize -= 1 self.perDown(1) return retval def buildHeap(self, alist): i = len(alist) // 2 self.currentSize = len(alist) self.heapList += alist[:] while i > 0: self.perDown(i) i -= 1 class HeapList(object): """大頂推""" def __init__(self): self.heaplist = [0] self.size = 0 def buildHeap(self, alist): i = len(alist) // 2 self.size = len(alist) self.heaplist += alist[:] while i > 0: self.percDown(i) i -= 1 def percUp(self, i): while i // 2 > 0: if self.heaplist[i] > self.heaplist[i // 2]: self.heaplist[i], self.heaplist[i // 2] = self.heaplist[i // 2], self.heaplist[i] i //= 2 def insert(self, k): self.heaplist.append(k) self.size += 1 self.percUp(self.size) def maxChild(self, i): if i * 2 + 1 > self.size: return i * 2 else: if self.heaplist[i * 2] > self.heaplist[i * 2 + 1]: return i * 2 else: return i * 2 + 1 def percDown(self, i): while i * 2 <= self.size: mc = self.maxChild(i) if self.heaplist[i] < self.heaplist[mc]: self.heaplist[i], self.heaplist[mc] = self.heaplist[mc], self.heaplist[i] i = mc def delMax(self): retval = self.heaplist[1] self.heaplist[1] = self.heaplist[self.size] self.size -= 1 self.heaplist.pop() self.percDown(1) return retval # 採用大頂堆的方式,製作容量為 k 的大頂堆,向堆中新增元素時,比堆頂值小,就彈出堆頂,並將此元素新增進堆。這就保證,最後遍歷完成後, # 我們獲得了比堆頂小的 k-1 個最小值 # 時間複雜度 O(nlogK) 因為只維護 K 大小的堆 class Solution: def getLeastNumbers(self, arr, k): if k == 0: return [] heaplist = HeapList() heaplist.buildHeap(arr[:k]) for i in arr[k: ]: if i < heaplist.heaplist[1]: heaplist.delMax() heaplist.insert(i) return heaplist.heaplist[1:] if __name__ == '__main__': solution = Solution() arrlist = [1, 2, 3, 4, 5, 6, 7, 8] res = solution.getLeastNumbers(arrlist, 3) print(res)