概述
堆是一种 完全二叉树 ,是一种从上到下,从左到右构建的二叉树。
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
在 Java - PriorityQueue 源码分析 内,对堆排序进行了讲解,。
堆是一个典型的,用物理上线性表示逻辑上非线性的数据结构 ,用数组存储,用二叉树表示逻辑。
例如下面这个例子的下标排列顺序,数组顺序请注意结点下标:
堆的下标关系:
- 根节点下标为0
- 若节点 P 的下标为 i,则左孩子为 2i+1,右孩子为 2i+2
- 若节点 P 的下标为 i,则父节点的下标为 (i-1)/2
大顶堆和小顶堆
堆结构分为两种:大顶堆和小顶堆 。
按照字母意思就可以理解。。。
大顶堆是根结点在整个堆中最大结点,小顶堆则相反。
在大顶堆中,最大值是根节点,最小值却不一定,这和元素的插入顺序有关系。
堆的构建
以小顶堆为例子,因为在 PriorityQueue 源码分析 内已经画过构建顺序图了,就直接拿来用了。
思想都是一样的,只是在实现中会有语法不同。
如上图,是在一个小顶堆中,插入一个新元素。PriorityQueue的实现过程中定义了几个中间变量,具体思路为:
-
在按照完全二叉树的构建规则,从上到下,从左到有插入元素。
-
新插入的元素和父元素比较
-
按照小顶堆规则,若比父元素要小,则和父元素交换。
-
重复上浮步骤直至父元素比它小为止
移除结点
移除结点应该区分为移除根节点和移除根的子树结点。
但是,实际上两者并没有区别,先看以下图片:
和添加元素类似,思路为:
-
先移除指定元素,然后将完全二叉树最后一个元素取出
-
将最后一个元素放置到移除元素的位置
-
如果它的左右子树中存在比它小的元素,或者都比它小,选择左右子树中较小的那个进行互换
-
重复上述步骤直至为叶子结点,或者左右子树都比它大