【c语言】堆排序——完全二叉树,时间:NlogN

说到排序,我们不得不提及堆排序,说到堆排序,我们就不禁想到了完全二叉树!!!

别问我为什么会这么想,因为他们本来就是一家人!!!

所以在学习堆排序之前,我们要先学习以下完全二叉树的一些性质和用法:

/*
堆:完全二叉树
i:
	左孩子:2*i+1
	右孩子:2*i+2
	父:(int)(i-1)/2
一个数组可以看作一个完全二叉树(堆)
	大根堆
		所有子树的最大值是这个根
	小根堆
		所有子树的最小值是这个根
	注:大根堆不一定是从大到小排序的数组,但从大到小排序的数组一定是大根堆
*/

注意这里父坐标的求法:(int)(i - 1) / 2!

问题1:当i = 0的时候,父坐标是多少呢?也就是,当一个结点的坐标是0的时候,他的父节点的坐标是多少?

答案是:0!也就是不会出现索引越界的问题!!!

话不多说,我们先放代码:

首先堆有两个特点:

1.大根堆的形成:(我们把数组看成一个完全二叉树!再生成这个树的同时产生大根堆)

// 生成大根堆
void heapInsert(int *arr, int index)
{
	//把新加入索引处的数不断和父比较,使之成为大根堆
	while (arr[index] > arr[(index - 1) / 2])
	{
		arr[index] ^= arr[(index - 1) / 2] ^= arr[index] ^= arr[(index - 1) / 2];
		index = (index - 1) / 2;
	}
}

计算过程:

按照层序遍历的顺序(数组索引的顺序),依次对每个结点和其父节点(父节点再和父节点比较)进行比较,当遍历完整棵树的所有结点的时候这个完全二叉树就变成了堆。

2.进行挑选最大值!

因为大根堆的根节点就是最大值,所以我们直接得到i一个最大值10,之后我们在把10和树的最后一个结点数值交换,再把最后一个结点删掉,在重新生成一遍大根堆!!!

 重新生成大根堆的方法:

//某个数在index位置,判断能否往下移动
void heapify(int *arr, int index, int heapsize)
{
	int left = index * 2 + 1;
	while (left < heapsize)
	{
		//两个孩子比,选出较大的孩子
		int largest = left + 1 < heapsize && arr[left + 1] > arr[left] ? left + 1 : left;
		//较大的孩子和父亲比,选出较大者的索引
		largest = arr[largest] < arr[index] ? index : largest;
		//如果父亲就是最大的,就跳出循环
		if (index == largest)
		{
			break;
		}
		//把最大值移到父亲位置
		swap(arr, index, largest);
		index = largest;
		left = index * 2 + 1;
	}
}

最后,我们把这两个处理堆的方法合并一下,每一次都得到一个最大值,就实现了堆排序:

//swap
void swap(int* arr, int x, int y)
{
	arr[x] ^= arr[y] ^= arr[x] ^= arr[y];
}

//堆排序
void heapsort(int* arr, int length)
{
	int heapsize = length;
	if (arr == NULL || heapsize < 2)
	{
		return;
	}
	for (int i = 1; i < heapsize; i++)
	{
		heapInsert(arr, i);
	}
	swap(arr, 0, --heapsize);
	while (heapsize > 1)
	{
		heapify(arr, 0, heapsize);
		swap(arr, 0, --heapsize);
	}
}

!!!亲测可行!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

活成自己的样子啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值