一、数据结构系列(堆篇)
1.1 堆的基本概念
堆结构是一棵完全二叉树,和普通的完全二叉树不同,堆对树中节点的取值做了如下的限制:
【1】对于堆中的任意节点,它的值总是大于其左右孩子的取值。
【2】对于堆中的任意节点,它的值总是小于其左右孩子的取值。
如果限制规则是【1】,那么称这种堆为大顶堆。
如果限制规则是【2】,那么称这种堆为小顶堆。
下面的讲解均以大顶堆为例,小顶堆和大顶堆情况很类似
1.2 堆结构示意图
1.3 堆的基本性质
-
堆顶一定始终存放着整个堆中最大值或者最小值,这取决于当前是大顶堆还是小顶堆。
-
如果对堆中的每一个节点从上到下,从左到右的顺序进行编号,编号从
1
开始那么节点编号存在如下关系如果某节点
id
为i
,那么该节点的左孩子编号为2*i
,右孩子编号为2*i+1
。
1.4 堆的存储结构
由于堆是一棵完全二叉树,因为完全二叉树的特殊性,除了最后两层存在叶子节点外,其它每层都是满的,因此可以使用数组来作为完全二叉树的存储结构,因此大多数的堆都使用数组来表示。
1.5 堆的基本操作
【1】插入操作。
【2】删除堆顶元素。
【3】降低堆中任意一个节点关键字的值。
【4】增加堆中任意一个节点关键字的值。
上述四个操作均可能会破坏堆的性质1
,因此需要采用某种操作,将破坏的堆性质进行恢复,主要包含如下两个基本调整操作:
【1】上滤调整(percolate up)。
【2】下滤调整(percolate down)。
1.6 上滤调整(percolate up)
如下图所示,初始时id为7的节点的值破坏了大顶堆的性质,因此需要上滤调整,上滤调整的基本步骤如下,这里设待上滤的节点编号为X:
【1】判断节点X是否有父亲节点,如果有转【2】,否则转【3】
【2】比较X的值和其父亲节点的值,如果X的值比父亲节点的值大,那么交换二者的值,并将X设置为父节点编号,然后转【1】,否则转【3】
【3】上滤结束
1.7 下滤调整
如下图所示,初始时id为1的节点的值破坏了大顶堆的性质,因此需要下滤调整,下滤调整的基本步骤如下,这里设待下滤的节点编号为X:
【1】判断节点X是否有左孩子(即X不是叶子节点),如果有转【2】,否则转【3】
【2】判断X是否还有右孩子,如果有那么取左右孩子中值最大的那个和X进行值交换,否则直接让左孩子和X交换,然后更改X为和旧X进行值交换的那个孩子节点,转【1】
【3】下滤结束
1.8 堆的插入算法
如果堆满,那么插入失败,否则将新插入的元素放在堆中最后一个元素编号的下一个编号的位置上,然后从该位置进行上滤调整,即可完成新元素的插入过程。
1.9 删除堆顶元素算法
如果堆空,那么删除堆顶元素失败,否则将堆顶元素取出,然后将堆中最后一个元素放在堆顶处,最后从堆顶处开始下滤调整,即可完成堆顶元素的删除过程。
1.10 降低堆中任意一个节点关键字的值
将某个节点关键字值降低之后,从该节点处进行下滤调整即可
1.11 增加堆中任意一个节点关键字的值
将某个节点关键字值增加之后,从该节点处进行上滤调整即可