1、堆的概念
如果有一个关键码的集合 K={K0,K1,K2,…,Kn-1},把所有完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i +1 且 Ki <= K2i + 2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
-
堆中每个节点的值总是不大于或不小于其父节点的值;
-
堆是一棵完全二叉树
2、堆的存储方式
二叉堆是一棵完全二叉树,所以很容易用数组表示,因为一棵高度为 h 的完全二叉树有 2h到 2(h+1)-1个节点,用数组存放一个二叉堆就不会太浪费空间,而且一旦知道高度,就可以知道节点数的范围。而且非常节省存储空间。因为不需要存储左右子节点的指针,单纯通过数组的下标就可以找到一个节点的左右子节点和父节点。
假设i为节点在数组中的下标,则有:
如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2
如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子
如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子
3、堆的创建
将数组"原地"的建成一个堆,不借助辅助空间
方式一:利用在堆中插入元素的思路,尽管数组中包含 n 个元素,可以假设起初堆中只包含一个数据,就是下标为 1 的数据。然后调用插入操纵,将下标从 2 大牌 n 的数据依次插入到堆中,这样就将包含 n 个数据的数组,组织成堆。
方式二:对一组普通的序列向上调整或者向下调整从而形成堆,这个过程可以称为“堆化”(堆化就是顺着节点所在路径,向上或向下对比然后交换)。
对以下序列{7 5 19 8 4 1 20 13 16} 画图理解向上调整的过程
以下图中关于堆中的数据都是从数组下标为 1 的位置开始存储的,所以注意左右孩子和父节点的计算其实也可以从 0 开始,处理思路不变,只是代码实现的时候计算子节点和父节点的下标公式发生变化了。如果节点的下标是 i,那左子节点的下标就是 2i+1,右子节点的下标就是 2i+2,父节点的下标就是 (i-1)/2。
代码实现:
private static void buildHeap(int[] a, int n) {
for (int i = n/2; i >= 1; --i) {
heapify(a, n, i);