排序算法10----堆排序(C)

        堆排序是借用数据结构堆来进行排序的一种算法,所以要想弄明白堆排序,首先要弄明白堆。

        首先我们先回顾一下堆:

        大堆:头大尾小,父结点 >= 子结点

        小堆:头小尾大,父结点 <= 子结点

        堆排序就是借用大堆和小堆来进行排序。

        那么问题来了?升序是用小堆吗?NO!NO!NO!这里许多人都会误以为升序小堆,降序大堆,现实是:升序大堆降序小堆

        我们知道,堆顶元素是堆里面MAX或者MIN元素,但是其它位置的元素,我们并不知道它在整个堆中的大小。我们仅仅知道堆顶元素的大小

        以升序大堆为例:大堆堆顶元素是最大的一个,那么我们将堆顶元素与最后一个元素交换,然后将除了最后一个元素之外的其他堆中元素进行调整,继续成为大堆,此时堆顶元素为次大值;再将堆顶元素与倒数第二个元素交换。反复如此,最终数组的末尾到开头就是最大,次大,次次大,.....,最小。这就成了升序。

        因此:从中我们得到了堆排最重要的几个东西:建堆,交换,调整

        下面以升序大堆为例:

        1、向下调整算法(大堆)

        建堆在前面树那里已经讲过,这里不多讲解。这里我们采用向下调整法建堆。直接上代码:

void AdjustDown_BigHeap(int* arr, int n, int parent)
{
	int child = 2 * parent + 1;
	while (child < n)
	{
		if (arr[child] < arr[child + 1] && child + 1 < n)
			child = child + 1;
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * child + 1;
		}
		else
			break;
	}
}

        2、 建堆,交换,调整

        我们从最后一个非叶子的结点开始向下调整,将最小子堆建成大堆;再逐渐向上走,将次小子堆建成大堆.........直到走到堆顶元素,向下调整,最终就建成一个大堆。

        思想:先子堆,后整堆

        完成建堆后,将堆顶元素与末尾元素交换。

        再继续向下调整,再交换,直到堆顶变成最小元素。

void HeapSort_incline(int* arr, int n)
{
	//将数组建成大堆
	//最后一个叶结点的父结点就是最后一个非叶子的结点
	for (int i = ((n - 1) - 1) / 2; i >= 0; i--)
	{
		AdjustDown_BigHeap(arr, n, i);
	}

	//建成之后,交换,调整
	for (int i = n - 1; i > 0; i--)
	{
		//交换堆顶元素和倒数第一,第二....的元素
		Swap(&arr[0], &arr[i]);

		//调整
		//每次末尾交换过去的元素不再参与调整,恰好每次需要调整的就是i个
		AdjustDown_BigHeap(arr, i, 0);
	}
}

        3、实现效果

	int arr[] = { 3,4,8,10,1,7,1,5,2,8,2,-1,-3 };
	int n = sizeof(arr) / sizeof(int);
	printf("原数组: ");
	PrintArray(arr, n);
	printf("\n");

	printf("排序后: ");
	HeapSort_incline(arr,n);
	PrintArray(arr, n);

        

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夹心宝贝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值