算法 之 堆 - 排序

给出数组A[1...n],我们可以将其中的元素用下面的方法以非降序有效地排序。

首先将A变换成堆,并使其具有这样的性质:每个元素的键值是该元素本身,即key(A[i])=A[i],1 ≤ i ≤ n。

转换成堆之后,由于A中各项的最大值存储在A[1]中,可以将A[1]和A[n]交换,使得A[n]是数组中的最大元素。这时A[1]中的元素可能小于存放在它的一个子节点中的元素,于是用过程Sift-down将A[1...n-1]转换成堆。接下来将A[1]和A[n-1]交换,并调整数组A[1...n-2]成为堆。交换元素和调整堆的过程一直重复,直到堆的大小变成1为止,这时,A[1]是最小的。

 

过程  HeapSort

输入  n个元素的数组A[1...n]

输出  以非降序排列的数组A

 

算法描述

for j ← n downto 2

    互换 A[1]和A[j]

    Sift-down(A[1...j-1], 1)

end for

 

注意这里算法描述的数组的索引都是1...n,而不是大家习惯的0...n-1。

 

创建堆需要Θ(n)的时间,Sift-down运算需要O(log n)时间,并且要重复n-1次,也就是用该算法给n个元素排序需要时间O(n log n)。 

// heap[0]用来存储数组中堆数据的长度,堆数据heap[1]...heap[heapLength]
// 所以数组的实际长度是heapLength+1,我们只对从数组索引为1开始的heapLength个数据进行操作

void siftDown(int* heap, int siftDownTo, int index)
{
	if (index < 1 || index * 2 > siftDownTo)
		return;

	bool done = false;
	while(!done && index * 2 <= siftDownTo)
	{
		index *= 2;

		if (index + 1 <= siftDownTo && heap[index + 1] > heap[index])
			index += 1;

		if (heap[index] > heap[index / 2])
		{
			int temp = heap[index];
			heap[index] = heap[index / 2];
			heap[index / 2] = temp;
		}
		else
		{
			done = true;
		}
	}
}

void heapSort(int* heap)
{
	if (heap == NULL)
		return;

	int heapLength = heap[0];
	int temp = 0;

	for (int i = heapLength; i >= 2; i--)
	{
		temp = heap[1];
		heap[1] = heap[i];
		heap[i] = temp;

		siftDown(heap, i - 1, 1);
	}
}

 

我使用的数组是这样定义的:

const int HEAP_LENGH = 10;
int heap[HEAP_LENGH + 1] = { HEAP_LENGH, 20, 11, 9, 10, 5, 4, 5, 3, 7, 3 }; 
heapSort(heap);

 

更多内容请参考:

算法 之 堆 - 简介

算法 之 堆 - Sift-up和Sift-down

算法 之 堆 - 插入和删除

算法 之 堆 - 创建堆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值