用c实现花样排序算法(3)——堆排序

目录

1.了解什么是堆

2.利用堆进行升序排序


1.了解什么是堆

堆实质上是数组,但在逻辑上可以认为是一颗完全二叉树。例如下图:

堆的还原过程中数据的下标有如下的结论:

左孩子=父亲(根)*2+1;

右孩子=父亲*2+2;

但直接还原出的堆并不能帮助我们解决问题,为此我们要了解大堆和小堆的概念。

大堆即根大于左子树同时大于右子树,小堆则同时小于。

大堆的堆顶数据即最大数据,小堆的堆顶数据即最小数据。

例如想要排出大堆需要如何做呢?

A.在左右子树已经是大堆时:

void AdjustDown(int* arr, int sz, int root)
{
	int parent = root;//确定父节点位置
	int child = parent * 2 + 1;//左孩子下标
	while (child < sz)
	{
		if (arr[child] < arr[child + 1] && child < sz - 1)
		{
			child++;//因为要排大堆,选左右中大的。
		}
		if (arr[child]>arr[parent])
		{
			Swap(&arr[child], &arr[parent]);//交换父亲和孩子
			parent = child;//赋值继续向下排序
			child = parent * 2 + 1;//重新确定左孩子下标
		}
		else
			break;//如果孩子节点比父亲结点小则该堆已经是大堆
	}
}

B.因为不可能一个堆开始便符合A情况,为了处理这种情况需要从最后一个父亲往前处理:

void SortDown(int* arr, int sz)
{
	int i = 0;
	for (i = (sz - 2) / 2; i >= 0; i--)
	{
		//(sz-2)/2是最后一个孩子节点父亲的下标,从后往前处理。
		AdjustDown(arr, sz, i);
	}
}

通过这两步即可完成大堆的创建。

2.利用堆进行升序排序

首先要确定升序要利用大堆或是小堆,开始想必大家肯定会选择小堆,天真地认为从堆顶不断取出数据就可以完成升序排序。但仔细思考一下如果拿出堆顶的数据,剩下的数据就不容易重新排序了。对比大堆,大堆第一次可以将堆顶和最后一个位置交换位置,再从堆顶排到倒数第二的数据即可。循环往复即可升序。

看看代码和结果吧:

int main()
{
	int arr[] = { 9, 4, 5, 7, 2, 8, 1, 0 };
	int len = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	SortDown(arr, len);//先排成大堆
	for (i = 0; i < len; i++)
		printf("%d ", arr[i]);
	printf("\n");
	int end = len - 1;
	while (end>0)
	{
		Swap(&arr[0], &arr[end]);//将最大的数放在末尾
		SortDown(arr, end);//再将除去末尾数之外的数再排一次大堆
		end--;
	}
	for (i = 0; i < len; i++)//成功排成升序
		printf("%d ", arr[i]);
	return 0;
}

 

 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不会敲代码的运气选手^

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

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

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

打赏作者

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

抵扣说明:

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

余额充值