堆排序

堆排序

堆排序是建立在堆结构的基础上的,是堆的一个应用实例

由前面我们已经知道了,从一个毫无逻辑的初始序列到建堆完成,可以得到堆顶是整个序列中最大的元素.那么就很容想到如果每次都从堆顶取走最大元素,序列不就有序了吗. 总体思想是这样的没错,但是还有很多细节需要考量,比如取走堆顶之后堆顶放哪;谁来做新的堆顶元素,怎么调整;这个算法的效率如何.

好,下面来解决这些问题

还是以最开始的序列 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,树状图变为

graph TD C[0] C-->D[8] C -->E[4] D-->F[6] D-->G[7] E-->E1[2] E-->E2[3] F-->F1[1] F-->F2[9]

此时,新的堆顶元素很可能已经不满足堆序性了,为了确保其满足堆序性,我们对新的堆顶元素进行一次下滤操作,这样树状图就变为:

graph TD C[8] C-->D[7] C -->E[4] D-->F[6] D-->G[0] E-->E1[2] E-->E2[3] F-->F1[1] F-->F2[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);//对堆顶元素进行下滤操作,调整树为堆结构
	}
}
posted @ 2019-09-20 15:15  dekeshile  阅读(101)  评论(0编辑  收藏  举报