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

发布时间:2024年01月18日

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

? ? ? ? 首先我们先回顾一下堆:

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

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

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

? ? ? ? 那么问题来了?升序是用小堆吗?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);

????????

文章来源:https://blog.csdn.net/2302_80873119/article/details/135663263
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。