堆的定義python
>=(大頂堆)或<=(小頂堆)
左右子樹節點的值堆中節點的關係算法
i/2
2*i
, 右子樹節點是2*i+1
徹底二叉樹特色:
若是一個徹底二叉樹有n個節點, 那麼從n/2+1個節點開始到n都是葉子節點數組
# coding:utf-8 """ 空間複雜度: O(1) 原地排序 時間複雜度: O(nlogn) 不穩定, 由於最後一個節點跟堆頂節點互換可能致使相同元素的順序互換 """ class MinHeap(object): """ 最小堆 """ def __init__(self, nums): self.heap_list = [0] # 填充0位置 self.size = 0 self.init_heap(nums) def insert(self, data): """ 插入元素, 放到最尾部, 上浮 :param num: :return: """ self.heap_list.append(data) self.size += 1 self._go_up(self.size) def _go_up(self, i: int): """ 末尾元素上浮 :param i: :return: """ while int(i / 2) > 0: parent = int(i / 2) if self.heap_list[i] < self.heap_list[parent]: self.heap_list[i], self.heap_list[parent] = self.heap_list[parent], self.heap_list[i] i = parent def pop_top(self): """ 刪除堆頂元素, 使用最後一個值移動到頂部, 再進行下浮 :return: """ if self.size >= 1: top_value = self.heap_list[1] self.heap_list[1] = self.heap_list[self.size] self.heap_list.pop() self.size -= 1 self._go_down(1) return top_value else: raise Exception("Heap Empty") def _go_down(self, i: int): while (2 * i) <= self.size: min_child_pos = self._get_min_child(i) if self.heap_list[i] > self.heap_list[min_child_pos]: self.heap_list[i], self.heap_list[min_child_pos] = self.heap_list[min_child_pos], self.heap_list[i] i = min_child_pos def _get_min_child(self, i: int): """ 找出i節點左右子樹中較小的節點 :param i: :return: """ left = 2 * i right = 2 * i + 1 if right > self.size: return left elif self.heap_list[left] < self.heap_list[right]: return left else: return right def init_heap(self, nums: list): """ 構造堆. 徹底二叉樹中從 n/2 開始都是葉子節點, 因此只須要讓非葉子節點下沉 :param nums: :return: """ start_pos = len(nums) // 2 self.size = len(nums) self.heap_list.extend(nums) while start_pos > 0: self._go_down(start_pos) start_pos -= 1 if __name__ == "__main__": nums = [9, 4, 7, 1, 8, 20] mh = MinHeap(nums) mh.insert(2) mh.insert(17) res = [mh.pop_top() for _ in range(5)] assert res == [1, 2, 4, 7, 8]
高性能定時器
好比一個定時器中維護了不少的定時任務, 每一個任務都設定了一個觸發執行的時間點, 定時器每過一個很小的單位時間(好比0.1s), 就會掃描一遍任務, 若是有任務是當前時間, 就觸發執行.
每過0.1s掃描所有任務效率會很低, 因此把全部任務放入一個最小堆中, 堆頂存儲的是最早執行任務. 定時器能夠根據堆頂任務的執行時間獲得一個時間間隔T, 能夠直接過T時間後再來檢查數據結構
爬蟲任務的優先隊列
二叉堆經常使用在爬蟲的優先級隊列中, 把任務按照優先級放入二叉堆, 調度器能夠拿堆頂元素, 保證拿到的是優先級最高的task.app