堆排序
堆排序
堆排序是建立在堆结构的基础上的,是堆的一个应用实例
由前面我们已经知道了,从一个毫无逻辑的初始序列到建堆完成,可以得到堆顶是整个序列中最大的元素.那么就很容想到如果每次都从堆顶取走最大元素,序列不就有序了吗. 总体思想是这样的没错,但是还有很多细节需要考量,比如取走堆顶之后堆顶放哪;谁来做新的堆顶元素,怎么调整;这个算法的效率如何.
好,下面来解决这些问题
还是以最开始的序列 3 1 2 8 7 5 9 4 6 0 为例
假设现在我们已经建好了堆结构,得到的序列 为 9 8 4 6 7 2 3 1 0 (层次遍历)
此时二叉树中最大的堆顶元素 9 放在数组 的开始位置即 heap[1] ,初始待排序的范围为[1,n] (注:这里数组下标从 1 开始)
我们取走 9 ,可以再开设一个数组存放我们取走的元素.但其实还有一个更巧也更节约空间的办法.
因为取走堆顶元素9以后,我们需要新的堆顶元素,此时我们并不知道剩下的元素中谁是最大的元素,所以不妨将堆顶元素和末尾的叶子结点交换,将叶子结点放在堆顶元素的位置,好,经过这样交换后,序列变为 0 8 4 6 7 2 3 1 9,树状图变为
此时,新的堆顶元素很可能已经不满足堆序性了,为了确保其满足堆序性,我们对新的堆顶元素进行一次下滤操作,这样树状图就变为:
过程是:0 先和 8 交换, 然后 0 又和7交换, 0找到其正确的位置. 8也成为新的堆顶元素
注意,此时我们的待排序数组范围变为了 [1,n-1], 位置 n 已经存放了元素 9 了,排好序的范围为[n].我们不需要再管它.
下一次就把待排序的堆的范围看做 [1,n-1],取走堆顶元素(即堆顶元素和末尾元素交换)后,排好序的范围变为[n-1,n],待排序堆的范围变为[1,n-2],
待排序范围 [1,n-2] , 排好序范围 [ n-1,n]
待排序范围 [1,n-3] , 排好序范围 [ n-2,n]
待排序范围 [1,n-2] , 排好序范围 [ n-3,n]
.........
待排序范围 [1,1] , 排好序范围 [ 2,n]
待排序范围 [] , 排好序范围 [ 1,n]
这样就完成了堆排序了
下面是示例代码:
/*
堆排序
*/
void heapSort()
{
createHeap();//对初始序列创建堆结构
for(int i=n;i > 1;i--)
{
swap(heap[1],heap[i]);//交换堆顶元素和末尾叶子结点元素
downAdjust(1,i-1);//对堆顶元素进行下滤操作,调整树为堆结构
}
}