堆常用来实现优先队列。 用数组保存数据,而不是链表。
在队列中,操作系统调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种(完全二叉树) 完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树
最大(最小)堆是一棵每一个节点的键值都不小于(大于)其孩子(如果存在)的键值的树。大顶堆是一棵完全二叉树,同时也是一棵最大树。小顶堆是一棵完全完全二叉树,同时也是一棵最小树。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
如下图所示,图一为最大堆,图二为最小堆:
以小根堆为例: 堆可以用数组存储数据,如有数组:{8,5,2,9,3,7,1,4,6} 则可以构成堆:
image.png
可以发现:任意节点的左右孩子对应数组下标的一半为其父节点对应的下标(5/2==4/2==2)。 注意:这里下标从1开始计算而不是从0开始,因为从0开始的话根节点的下标和子节点下标间就没有了倍数关系(5/2 != 6/2)
从当前结点开始,和它的父亲节点比较,若是比父亲节点来的小,就交换,然后将当前询问的节点下标更新为原父亲节点下标;否则退出。
经过上浮操作之后,下标3处节点的元素值如下图所示
让当前结点的左右儿子(如果有的话)作比较,哪个比较小就和它交换,并更新询问节点的下标为被交换的儿子节点下标,否则退出。
每次插入的时候呢,都往最后一个插入,然后使它上浮。
让根节点元素和尾节点进行交换,然后让现在的根元素下沉就可以了。
根节点数组下标必定是 0,返回堆数组中下标为 0 的元素即可。
见算法 - 排序系列文章第六篇,同时用代码实现上述对堆的操作。