堆的定义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