一、基本信息
1、本质
一颗特殊的树。
2、特性
- 完全二叉树。
- 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。
3、分类
对于每一个节点的值都大于等于子节点的值的情况,该堆被称为大顶堆。
对于每一个节点的值都小于等于子节点的值的情况,该堆被称为小顶堆。
4、存储方式
对于完全二叉树而言,数组存储方式是最节省内存的。
5、插入节点的时间复杂度
将节点插入到靠左的底层作为新的叶子节点,之后逐层比较交换,使得该树的每一个节点均大于或者小于子节点。故插入节点之后的堆化的时间复杂度为树的高度,即:O(logn) 。
6、删除堆顶节点的时间复杂度
删除堆顶节点之后将一叶子节点放到堆顶,之后从上到下逐层交换,使得该树的每一个节点均大于或者小于子节点。故删除堆顶节点之后的堆化的时间复杂度为树的高度,即:O(logn) 。
二、实际应用
1、查找第K大(小)元素
构建一个 K 大小的小顶堆,遍历数组与堆顶元素比较,如果比堆顶元素大就删除堆顶数据,把该数据插入堆中,否则就比较下一个。最后得到的小顶堆内的 K 个元素就是前 K 大的元素。
2、优先队列
(1)高性能定时器
比如一个定时器中维护了很多的定时任务,每个任务都设定了一个触发执行的时间点,定时器每过一个很小的单位时间(比如0.1s)就会扫描一遍任务,如果有任务是当前时间,就触发执行。
每过 0.1s 扫描全部任务效率会很低,所以把所有任务放入一个最小堆中,堆顶存储的是最先执行任务。定时器可以根据堆顶任务的执行时间得到一个时间间隔 T,可以直接过 T 时间后再来检查。
(1)爬虫任务的优先队列
二叉堆常用在爬虫的优先级队列中,把任务按照优先级放入二叉堆,调度器可以拿堆顶元素,保证拿到的是优先级最高的 task。
(SAW:Game Over!)