既然要说堆排序,那么必然要说说什么是大根堆,小根堆了。
大根堆: 若根节点存在左右子节点,那么根节点的值大于或等于左右子节点的值。
小根堆: 若根节点存在左右子节点,那么根节点的值小于或等于左右子节点的值。
通俗来说,那顾名思义,大根堆就是根节点比左右孩子都要大或者等于的二叉树,小根堆就是根节点比左右孩子都要小或者等于的二叉树。
那么我们可以总结出关于大根堆和小根堆的结论:
(1)、堆是一棵完全二叉树;
(2)、小根堆的根节点是堆中最小值,大根堆的根节点是堆中最大值;
(3)、堆适合采用顺序存储。
堆最重要的两个方法就是插入和删除方法。
下面来说说堆的插入方法:
堆的插入算法: 将一个元素插入到堆中,使之依然成为一个堆。
算法描述:先将结点插入到堆的尾部,则从该节点的父节点出发到跟结点就是一个有序序列,那么其实就是将该元素插入到一个有序序列中的操作,类似于简单的插入排序算法。具体步骤是将该节点逐层向上调整,直到依然构成一个堆,调整方法是看每个子树是否符合大(小)根堆的特点,不符合则调整根和叶子节点的位置。
算法步骤:(1)将该元素插入到堆的尾部;(2)如果不满足堆的特性,进行调整,直到所有结点都满足条件。
堆的删除算法: 堆在删除元素时,只可以删除根节点,然后使剩下的结点依然成为一个堆。
算法描述:将根节点删除后用堆尾元素填充,然后调整二叉树,使之依然成为一个堆。
算法步骤:(1)删除根节点,用堆中最后元素进行填充;(2)如果不满足堆的特性,进行调整,直到所有结点都满足条件。
堆的构建过程其实就是构建一个符合大根堆或者小根堆的完全二叉树,那么就可以使用顺序表来进行存储。
下面举例说明堆的构建过程:
将无序序列 [49,38,65,97,76,13,27,40 ]构建成大根堆:
第一步:
第二步:插入结点38
第三步(1):因为要建立大根堆,49和65不符合大根堆特点,对其进行调整:
第三步(2):调整后:
第四步(1):插入结点97,发生冲突,进行调整
第四步(2):还有冲突,继续调整
第四步(3):调整后
第五步(1):插入结点76,发生冲突,进行调整
第五步(2):调整后
第六步:插入结点13
第七步:插入结点27
第八步(1):插入结点40,发生冲突,进行调整