堆排序

堆排序是一种排序算法,通过构建最大堆并不断调整堆来完成排序。文章介绍了堆排序的思想,包括如何调整堆和两种构造堆的方法,并重点讲解了通过下沉法优化效率的过程。最后,提供了具体的实现代码片段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思想:将数组调整为一个堆,保证父节点不小于两个子节点,这样根节点(堆顶)就是所有元素中的最大值。不断取出根节点并重新调整堆,直到堆被取完即可完成排序。

技巧:

1.关于“不断取出根节点形成有序数组”,可以将堆顶(最大值)与堆的最后一个节点交换,然后缩小堆(排除已取出的节点),然后下沉堆顶到正确的位置即可得到新的已调整的堆;

2.构造堆有两种方式,一种是从堆顶往后遍历所有节点,每次都将当前节点与父节点进行比较,使其上浮到正确的位置;另一种是从最后一个非叶子节点开始往前遍历直到根节点,每次都将当前节点与子节点进行比较,使其下沉到正确的位置。

由于技巧1中也用到下沉法,所以使用第二种方法会更加方便,同时由于只需要从最后一个非叶子节点进行遍历,效率也更高。

实现代码如下:

void heapSort(int num[], int start, int end)
{
	//从最后一个非叶子节点开始往前调用sink调整堆
	//调用完之后该节点之后的节点都是已调整好的小堆
	//当根节点调用完成之后形成一个已调整好的大堆
	for(int i=(start+end-1)/2;i>=start;i--)
		sinkForHeapSort(num, i, start, end);//大顶堆
	
	//直到堆的大小为1,则数组升序排序完成
	for(int j=end;j>=start;)
	{
		swap(num[start], num[j]);//将堆顶的元素(最大值)与堆的最后一个节点交换
		j--;//缩小堆
		sinkForHeapSort(num, start, start, j);//重新调整堆
	}

}

代码中可以对num[]数组的任意区域(start~end)进行排序,因此父节点和子节点的下标满足下式:

(childPos+start-1)/2=parentPos

sinkForHeapSort的实现代码如下:

//对pos位置的元素进行调整,使其下降到正确的位置
void sinkForHeapSort(int num[], int pos, int start, int end)
{
	//(childPos+start-1)/2=parentPos
	if(pos<start||start>end) return;
	int childPos=pos*2-start+1;//左边子节点的坐标
	while(childPos<end)//如果有左边子节点和右边子节点
	{
		if(num[childPos]<num[childPos+1]) childPos++;//如果右边子节点比较大,则用右边子节点与父节点进行比较
		if(num[pos]>=num[childPos])break;//如果父节点比子节点都要大,则退出循环
		swap(num[pos], num[childPos]);//如果父节点较小,则与较大的子节点交换
		pos=childPos;//继续往下沉
		childPos=pos*2-start+1;
	}
	//只有左边子节点时,直接与左边子节点进行比较
	if(childPos==end && num[pos]<num[childPos]) swap(num[pos], num[childPos]);

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值