1.堆的特性
堆有大根堆和小根堆,大根堆的子树,父结点比子结点都要大,小跟堆的子树,父节点都要比子结点小。
堆有这样的特性:
- n个元素的堆的高度是 l o g n logn logn,因为堆是一棵完全二叉树或者近似一棵完全二叉树。
- 堆中,如果父节点的index是n,那么这个结点的左右子结点的index 分别是 2 ∗ n + 1 2*n+1 2∗n+1和 2 ∗ n + 2 2*n +2 2∗n+2,并且,如果堆总共有n个元素,并且根结点的index为0,堆中最后一个有子结点的父节点的index一定是 n / / 2 − 1 n//2 -1 n//2−1
- 最大堆,最大的元素在根节点,最小堆,最小的元素在根节点。
2.如何建堆
如何从一个无序的列表建起起一个大根堆或者小根堆呢?利用堆的特性,我们从最后一个有子节点的父节点开始进行调整,也就是索引值为 n / / 2 − 1 n//2 -1 n//2−1的结点。下面以建立小跟堆为例讲解。
-
首先我们拿到一个根节点root,检查结点root的两个子节点谁的值更小,注意需要保持两个子节点的索引值不超过堆的长度,超过了说明没有子节点。
-
比较较小的子节点和父节点谁的值小,如果子结点的值更小,则需要交换子结点和父节点。注意!!如果这里发生了交换,那么可能会影响原来较小子结点已经形成的堆,所以我们需要继续调整堆,所以这里我们可以用递归的写法。具体看代码中,如果用非递归的写法则是,我们要一直循环,向下找到这个父节点该插入的位置!!
这是递归写法
def sink(num_list, root, length):
if 2 * root + 1 < length:
child = 2 * root + 2 if 2 * root