零. 前言
堆作为一种重要的数据结构,在面笔试中经常出现,排序问题中,堆排序作为一种重要的排序算法经常被问道,大顶堆小顶堆的应用经常出现,经典的问题TopN问题也是堆的重要应用,因此,了解并掌握这种数据结构是很必要的。
一. 堆的数据结构
1.由树而来
堆的数据结构可以看作是一种由数组实现的抽象完全二叉树,通过大顶堆或者小顶堆,来达到快速找到一新数据在整个堆结构中的应有位置,继而来实现排序、TopN问题或者log级别的算法要求。
完全二叉树,就是在一棵树中,元素从从上到下,从左到右依次变满,不会出现一个节点的左子节点不存在而右子节点存在的情况。
2.大顶堆
在一个大顶堆中,根节点的值比左右子树都要大(可以等于),在所有子树中都成立,但注意此时,左右子节点的大小并没有进行比较,所以是未知。
一个典型的大根堆案例:
上图中的二叉树中的数值对应在数组中就是arr=[7,5,6,2,3,1,4],可以看作是树的层序遍历,从上到下,从左到右依次填满
3.小顶堆
在一个小顶堆中,根节点的值比左右子树都要小(可以等于),在所有子树中都成立,但注意此时,左右子节点的大小并没有进行比较,所以是未知。
案例同上,只不过大小相反,不再赘述。
4.数组实现堆中的对应关系
由数组实现方法中,会有数组下标和堆的抽象完全二叉树的对应关系,即数组中的第i元素在堆的哪个位置,或者说,堆中的元素映射在数组是哪个位置。
对于一个根节点i,它的左子节点是i*2+1,它的右子节点是i*2+2(如果存在的话,在实际中,可能左右子节点都不存在,会超出数组的实际长度,需提前判断)。
在下方的案例,元素6的下标在数组中对应2,2*2+1=5,数组中5对应的元素是1,而右子节点的元素是4,是一一对应的,而如果知道左子节点,或者右子节点,也可以反过来求根节点的在数组中的位置,对于一个左右子节点i,(i-1)/2即是根节点。
二. 堆构建
1.堆的构建过程
在手动构建堆的过程中,可以用以下的方式来手动构建一个堆【1】,默认为大顶堆:
在整个堆的构建过程中,就是
(1)依次添加每个元素
(2)比较新添加的元素是否比根节点大(默认为大顶堆)