- 堆的定义:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做大根堆,根节点最小的堆叫做小根堆。
- 堆的特性:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
- 如何构建堆:首先找到一个乱序的完全二叉树(这里任意取一个举例)
首先找到完全二叉树中最后一个不是叶子节点中的节点,也就是图中的21的位置,在代码中可以根据公式:(最后一个节点的位置 - 1) / 2.就是最后一个不为叶子节点的位置.
找到这个节点后向下查找(这里以小根堆为例),找到子节点中最小的节点,然后判断与自身的关系,若满足小根堆条件(parent < child),则退出,若不满足则交换节点的值,这里将16 与 21交换
交换之后,若parent为叶子结点(panent->leftchild越界)则退出,否则继续向下查找,直到parent为叶子结点或子树满足小根堆.这里21已经是叶子节点,所以退出向下查找过程.
之后找到倒数第二个不为叶子节点的节点,依上述步骤向下查找,直到将所有不为叶
子结点的节点都向下查找一遍.
这里继续将3向下查找,3的子树满足小根堆,退出向下查找.
之后继续向前遍历,找到节点12向下查找,在子节点中找到3 和 16中较小的3,不满足小根堆的性质,交换12 和 3,
交换完成之后12此处的节点依旧不是叶子结点,继续向下查找,找到叶子节点中较小的7,仍不满足小根堆的性质,继续交换
此时12 成为叶子结点,退出向下查找,由于根节点已经向下查找完毕,所以堆的构建也就完成了.此时一个乱序的完全二叉树就已经变成了一个小根堆.
接下来,看一下代码部分如何实现:
void Init(Data* val, heap