简介
堆排序 heapsort,是指利用堆这种数据结构所设计的一种排序算法。堆是完全二叉树,分为大顶堆和小顶堆。大顶堆的特点是指任何一个父节点的值,都大于等于它左右孩子节点的值。小顶堆的特点是指任何一个父节点的值,都小于等于它左右孩子节点的值。
文章中使用的动画网站地址:
限 pc: 排序算法动画 :http://www.donghuasuanfa.com/sort/heapSortPortal
算法一览表:https://blog.csdn.net/ww753951/article/details/106862328
排序过程
算法分为三步骤。
一:将数组构造成二叉树
二:将完全二叉树构造成大顶堆,树中所有父元素都比子元素大。构造大顶堆的步骤。1.首先从右至左,从下至上遍历非叶子节点,比较非叶子节点和俩个子节点的较大值,如果非叶子节点小于叶子节点较大值,则互换位置,保证调整后的非叶子节点大于子节点。2.互换位置后,因为有可能新的叶子节点比叶子节点的叶子节点还小,所以需要重复比较和互换位置的操作。维持大顶堆的结构。
三:循环删除堆顶元素,移到集合尾部。将最后一个元素移动到堆顶,调节堆产生新的堆顶。新的堆重复比较非叶子节点和叶子节点的步骤。保证堆的特点。
示例以3,4,2,1,6,5为数组进行演示。
演示的动画来源:堆排序算法动画地址 http://www.donghuasuanfa.com/sort/heapSortPortal
1.生成完全二叉树
首先将数组生成完全二叉树,数组3,4,2,1,6,5生成后的二叉树如下图所示。
2.构造大顶堆
1.首先从右至左,从下至上层序遍历非叶子节点,比较非叶子节点和俩个子节点的较大值,如果非叶子节点小于叶子节点较大值,则互换位置,保证调整后的非叶子节点大于子节点。
2.互换位置后,因为有可能新的叶子节点比叶子节点的叶子节点还小,所以需要重复比较和互换位置的操作。维持大顶堆的结构。
示例:
二叉树从右至左,从下至上层序遍历,当前二叉树最右下侧非叶子节点为2,所以首先遍历的节点为2。
获取节点2的两个叶子节点较大的节点,因为当前2节点只有一个节点5,所以获取的为5。再比较2和5的大小,因为构造的是大顶堆,且叶子节点5大于2。 所以需要互换位置。
继续遍历下一个节点,下一个非叶子节点为4。
获取节点4的两个叶子节点1和6较大的节点,所以获取的为6。再比较4和6的大小,因为构造的是大顶堆,且叶子节点6大于4。 所以需要互换位置。
继续遍历下一个节点,下一个非叶子节点为3。
获取节点3的两个叶子节点6和5较大的节点,所以获取的为6。再比较3和6的大小,因为构造的是大顶堆,且叶子节点6大于3。 所以需要互换位置。
因为交换位置后,交换后的节点不一定比子节点大。所以需要重新处理二叉树。例如示例所示。3节点交换位置后,比子节点要小,所以需要重新处理二叉树,满足大顶堆的特性。3节点找到两个子节点的较大值4。
因为构造的是大顶堆,且叶子节点4大于3。 所以需要互换位置。最后大顶堆的构造结束。
整体动图如下所示:
3.循环删除堆顶元素
循环删除堆顶元素,移到集合尾部。将最后一个元素移动到堆顶,调节堆产生新的堆顶。新的堆重复比较非叶子节点和叶子节点的步骤。保证堆的特点。
堆顶元素为6。末尾元素为2,交换位置后则6元素为已排序元素,如下图所示。
因为交换位置后,堆顶元素2小于子节点4和5, 所以不满足大顶堆性质。
需要重复构造大顶堆步骤,交换元素位置,调整二叉树,最终形成大顶堆。
然后重复步骤,再次交换元素位置,则5元素为已排序元素。
重复上述步骤,直至所有元素排序完成。
-------分割线-------
时间复杂度
最差时间复杂度 | 平均时间复杂度 | 最优时间复杂度 |
---|---|---|
O ( N ∗ l o g 2 N ) O(N*log_{2}N) O(N∗log2N) | O ( N ∗ l o g 2 N ) O(N*log_{2}N) O(N∗log2N) | O ( N ∗ l o g 2 N ) O(N*log_{2}N) O(N∗log2N) |
堆排序整体的时间复杂度为:O(N * log2N)。整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中第一部分构建初始堆经推导复杂度为O(n),
在第二部分交换并重建堆的过程中,需循环数组剩余元素,共交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)…1]逐步递减,所以循环剩余数组和每次数组调整堆的过程累计近似为N * log2N。因为第一部分的O(N)基本忽略。所以堆排序时间复杂度一般认为就是O(N * log2N)。
空间复杂度
堆排序只需要元素交换位置即可,无需额外空间, 所以空间复杂度为1。
稳定性
在构建大顶堆时,元素之间的顺序无法保证。所以为不稳定排序。