选择排序算法:直接选择排序和堆排序

🐱‍🐉🐱‍🐉导航

前言

 直接选择排序

✨基本思想:  

🎆🎆实现步骤:

 🎉🎉🎉代码如下:

🔔🔔🔔🔔特性总结:

堆排序

✨基本思想:  

🎆🎆实现步骤:

 🎉🎉🎉代码如下:

🔔🔔🔔🔔特性总结:


前言

  • 本篇博客主要介绍选择排序算法中的直接选择排序(SelectSort)堆排序(HeapSort)
  • 代码实现:C语言

 直接选择排序

✨基本思想:  

        每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

        🍊实际上,我们可以每一趟选出两个值,一个最大值一个最小值,然后将其放在序列开头和末尾,这样可以使选择排序的效率得到提高。

ps:选择排序的思路,我们可以在学校上第一次体育课时的场景,老师总是在一排中先挑出最高的同学排到队列右边,以此挑出次高的排到右二……


🎆🎆实现步骤:

前提:给定一组有N个元素的待排序列,要求排升序

  1. 定义两个下标begin和end,标记每次待排序列的起始位置和结束位置;定义两个下标mini和maxi,均赋初值begin,标记最小树和最大数的下标
  2. 在元素集合array[begin]--array[end]中选择关键码最小和最大的数据元素,并标记他们的下标分别为mini和maxi
  3. 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  4. 更新begin和end,重复上述步骤,直到集合剩余1个元素(begin > end 时结束)

借用网上的gif演示操作:这里只是每次选最小的


 🎉🎉🎉代码如下:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void SelectSort(int* a, int n)
{
	assert(n);

	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] < a[mini])
				mini = i;

			if (a[i] > a[maxi])
				maxi = i;
		}

		Swap(&a[begin], &a[mini]);
		//如果begin和maxi重叠,则说明max的值已经备换到了mini,此时要更新一下maxi
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);

		begin++;
		end--;
	}
}

🔔🔔🔔🔔特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用,比直接插入排序还拉😅
  2. 时间复杂度:O(N^2),最好情况也还是O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

堆排序

✨基本思想:  

        堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

        🍊关于堆的更详细的知识,这里不再过多赘述,感兴趣的读者请前往我的另一篇博客查看:➡传送门


🎆🎆实现步骤:

前提:给定一组有N个元素的待排序列,要求排升序

  1. 建堆:排升序,建大堆;排降序,建小堆。建堆过程利用堆的向下调整。
  2. 选数:利用堆删除的思想进行排序,每次选出堆顶元素,插到序列前面。这里也是利用堆的向下调整

这里展示一张流程图供读者自行走一遍思路:

 🎉🎉🎉代码如下:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void AdjustDwon(int* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		// 选出左右孩子中小/大的那个
		if (child + 1 < size && a[child + 1] > a[child])//大于 建大堆   小于 建小堆
		{
			++child;
		}

		// 孩子跟父亲比较
		if (a[child] > a[parent])//大于 建大堆   小于 建小堆
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

// 降序 -- 建小堆
// 升序 -- 建大堆
void HeapSort(int* a, int n)
{
	assert(n);
	// 建堆方式2:O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDwon(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDwon(a, end, 0);
		--end;
	}
}

🔔🔔🔔🔔特性总结:

  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

学习记录:

  • 本篇博客整理于2022.7.9
  •  请多多指教🌹🌹
  • 如果觉得写的不错,看完了别忘了点赞啊,感谢支持😏😏
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

如何写出最优雅的代码

感谢支持,我将继续努力!

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

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

打赏作者

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

抵扣说明:

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

余额充值