排序(2)——选择排序

三、选择排序

1.简介

        选择排序主要采取的排序策略就是选择,在拿到待排序数组后,程序会一遍遍地遍历未排序部分数组,在每一次的遍历过程中会找到最小的元素,并在遍历完成后换到未排序数组部分的最左侧。如此循环往复,每一次遍历选出一个最小的数据进行排序,最后达到整个数组有序。

         选择排序思想方法很简单,就是比较找到最小,然后交换,一次排好一个元素。我们也可以将选择排序做一些优化,比如每次选出一个最大的和一个最小的,分别排在左端和右端,这样排序是从两端同时开始,效率加倍。本文的选择排序就采取这种方法,一次遍历选出最大值和最小值。

2.思路与代码

        在写选择排序的时候,我们同样试着将单步的排序写出来,再加上循环生成最后的选择排序。

        假设此时区间[begin,end]需要排序,那么我们就需要对该区间进行遍历,找到最大值与最小值的下标(因为数组交换需要通过下标实现)。我们可以认为最小值和最大值下标分别为begin和end,当找到更小或更大的元素时修改变量赋值即可。在遍历结束后,将最小值与下标为begin的值交换,将最大值与下标为end的值交换。

        注意!此处可能存在如下情况:

        发生这种错误是因为最大值落在了begin位置,导致最小值交换之后maxi未进行更新,使得maxi指向的位置不再是最大值,而变成了新换过来的最小值。解决这个问题并不难,加个判断即可。于是我们可以得到单步排序代码。 

    int begin,end;
    int maxi = end, mini = begin;
	for (int i = begin; i <= end; i++)
	{
		if (a[i] > a[maxi])
		{
			maxi = i;
		}
		if (a[i] < a[mini])
		{
			mini = i;
		}
	}
	swap(&a[mini], &a[begin]);
	if (maxi == begin)
	{
		maxi = mini;
	}
	swap(&a[maxi], &a[end]);

        有现在的基础,再写出选择排序就不是什么难事了。我们只需要让begin与end分别从头和尾开始,每次排序后begin自增、end自减即可。

void swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int maxi = end, mini = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		swap(&a[mini], &a[begin]);
		if (maxi == begin)
		{
			maxi = mini;
		}
		swap(&a[maxi], &a[end]);
		begin++;
		end--;
	}
}

3.复杂度与稳定性分析

(1)时间复杂度

        选择排序的时间复杂度不难分析,无论数组的情况,都需要从头到尾慢慢遍历,是典型的等差数列,所以其时间复杂度是O(n^2)

(2)空间复杂度

        选择排序并未用到多余额外的空间,所以空间复杂度是O(1)

(3)稳定性

        选择排序是不稳定的。

        选择排序直观想象好像可以控制当a[i] == a[mini]时不改变mini,就可以成为稳定的。但是要敏锐地捕捉到其存在数据交换的情况,从而是有可能打乱相对顺序的。如:

        因而我们可以认为选择排序是不稳定的。 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

犀利卓

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

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

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

打赏作者

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

抵扣说明:

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

余额充值