摘要:

1,堆的介绍

2,堆中元素的添加

3,堆中元素的删除

4,堆的代码实现

5,堆排序中的建堆

1,堆的介绍

堆(Heap)是一种特殊的完全二叉树,堆中元素都有优先级,我们常说的优先队列(PriorityQueue)指的就是堆。

完全二叉树就是一棵二叉树除了最下面一层外,其它各层的节点数目均已达最大值,且最下面一层的所有节点从左向右连续紧密排列,这样的二叉树被称为完全二叉树。

如下图所示,第二个就不是完全二叉树,因为节点 3 有右子树没有左子树,最后一层不是从左往右紧密排列的。

堆一般分为两种,一种是最大堆(有的也叫大根堆,大顶堆),一种是最小堆。最大堆根节点的值是堆中最大的,最小堆根节点的值是堆中最小的。

两者原理差不多,这里只介绍其中一种,我们就拿最小堆来讲解。因为堆是一棵完全二叉树,所以如果知道子节点的下标,那么一定知道父节点的下标,如果知道父节点的下标也一定知道子节点的下标(假设有子节点)。

他们的对应关系如下:

父节点的下标 = (子节点下标-1) >> 1;
左子节点下标 = 父节点下标*2 + 1;
右子节点下标 = 父节点下标*2 + 2;

堆的常见函数如下,其中往堆中添加元素会往上调整,删除堆顶元素会往下调整,这个在下面添加和删除的时候都会有介绍。

public void add(int val);// 往堆中添加元素
public int poll();// 删除堆顶元素
public int peek();// 获取堆顶元素,不删除

2,堆中元素的添加

堆既是二叉树也是数组,添加元素的时候,按照数组的顺序添加,实际上相当于在完全二叉树中添加一个叶子节点。

因为堆中元素是有优先级的,添加完之后还要根据优先级进行往上调整。就是和父节点比较谁的值小(这里介绍的是最小堆),如果比父节点小就和父节点交换,交换完之后,还要继续往上比较 …… ,如果比父节点值大就不在交换,如下图所示。

这样通过不断的和父节点比较,如果添加的元素是堆中最小的,他最终会到根节点,也就是最小堆的根节点是堆中所有元素的最小值。如果添加元素不比父节点小,就不需要交换。