堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
归纳出堆排序算法的步骤:
1. 把无序数组构建成二叉堆。 2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。
堆是具有以下性质的完全二叉树:
大顶堆:每个结点的值都大于或等于其左右孩子结点的值
小顶堆:每个结点的值都小于或等于其左右孩子结点的值
对堆中的结点按层进行编号,将这种逻辑结构映射到数组中如下:
该数组从逻辑上讲就是一个堆结构,用简单的公式来描述一下堆的定义就是:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] 小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
1、将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
2、将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
3、由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
当我们删除一个最大堆的堆顶(并不是完全删除,而是替换到最后面),经过自我调节,第二大的元素就会被交换上来,成为最大堆的新堆顶。
上图所示,当我们删除值为10的堆顶节点,经过调节,值为9的新节点就会顶替上来;当我们删除值为9的堆顶节点,经过调节,值为8的新节点就会顶替上来.......
由于二叉堆的这个特性,我们每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么我们只要反复删除堆顶,反复调节二叉堆,所得到的集合就成为了一个有序集合,过程如下:
删除节点9,节点8成为新堆顶:
删除节点8,节点7成为新堆顶:
删除节点7,节点6成为新堆顶:
删除节点6,节点5成为新堆顶:
删除节点5,节点4成为新堆顶:
删除节点4,节点3成为新堆顶:
删除节点3,节点2成为新堆顶:
原本的最大堆已经变成了一个从小到大的有序集合。
二叉堆实际存储在数组当中,数组中的元素排列如下:
(1)算法复杂度
堆排序的时间复杂度,主要在初始化堆过程和每次选取最大数后重新建堆的过程;
初始化建堆过程时间:O(nlog2n)
最好、最坏平均情况都需要循环建堆,更改堆元素后重建堆时间:O(nlog2n)
堆排序的时间复杂度为:O(nlog2n)
堆排序就是选择排序,空间复杂度为常数:O(1)
(2)算法稳定性(不稳定)
堆的结构是节点i的孩子为2 * i和2 * i + 1节点,
大顶堆要求父节点大于等于其2个子节点,小顶堆要求父节点小于等于其2个子节点。
在一个长为n 的序列,堆排序的过程是从第n / 2开始和其子节点共3个值选择最大(大顶堆)或者最小(小顶堆),这3个元素之间的选择当然不会破坏稳定性。但当为n / 2 - 1, n / 2 - 2, ... 1这些个父节点选择元素时,就会破坏稳定性。有可能第n / 2个父节点交换把后面一个元素交换过去了,而第n / 2 - 1个父节点把后面一个相同的元素没有交换,那这2个相同的元素之间的稳定性就被破坏了。堆排序是不稳定的排序算法。
打印:
原文参考:https://blog.csdn.net/free377096858/article/details/90482650