选择排序

定义

**选择排序(Selection sort)**是一种简单直观的排序算法。

它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为。选择排序是不稳定的排序方法。

C++代码实现

void selectionSort(vector<int>& v, int begin, int end)
{
	int index = 0;	//用来记录最小元素索引
	int min = 0;	//用来记录最小元素

	for (int i = begin; i < end - 1; i++)
	{
		index = i;	//每趟排序前先假设未排序序列中的第一个元素为最小值
		min = v[i];
		for (int j = i + 1; j < end; j++)
		{
			if (min > v[j])
			{
				//发现后面有更小的则更新最小值
				min = v[j];
				index = j;
			}
		}
		//每趟排序过后,判断最小值索引是否更新
		if (index != i)
		{
			//更新了则交换当前位置(未排序序列第一个位置)元素和最小元素
			v[index] = v[i];
			v[i] = min;
		}
		//否则无需交换
	}
}

过程模拟

简单模拟,以[2, 2, 5, 1, 3]为例。
注意黑色加粗的2,用来判断选择排序算法的稳定性。

未排序序列:还未排好序的序列。排序开始之前整个序列都是未排序序列[2, 2, 5, 1, 3]。
已排序序列:每轮排序都会更新已排序序列。排序开始之前已排序序列为空[]。

第一轮排序(i = 0): 假设当前位置(即未排序序列的第一个位置)元素为最小值, min = v[i] = 2
j = 1, min = 2 == v[j] = 2, 无需更新最小元素及索引
j = 2, min = 2 < v[j] = 5, 小于无需更新
j = 3, min = 2 > v[j] = 1, 找到未排序序列中更小的元素,更新最小值min = 1,索引index = 3
j = 4, min = 1 < v[j] = 3, 无需更新
退出内层循环,最小值索引已更新,交换当前位置元素2和未排序序列中的最小元素1。
至此第一轮排序结束,比较次数为n - 1,时间复杂度为O(n)。
第一轮排序后,已排序序列更新为[1],即放到已排序序列的末尾, 未排序序列更新为[2, 5, 2, 3]。

第二轮排序(i = 1): 依旧假设min = v[i] = 2
j = 2, min = 2 < v[j] = 5, 无需更新
j = 3, min = 2 == v[j] = 2, 无需更新
j = 4, min = 2 < v[j] = 3, 无需更新
退出内层循环,最小值索引没有更新,无需交换
至此第二轮排序结束,比较次数为n - 2, 时间复杂度为O(n)。
第二轮排序后,已排序序列更新为[1, 2], 未排序序列更新为[5, 2, 3]。

第三轮排序(i = 2): min = v[i] = 5
j = 3, min = 5 > v[j] = 2, 更新min = 2,index = 3
j = 4, min = 2 < v[j] = 3, 无需更新
退出内层循环,最小值索引更新,交换当前位置元素5和未排序序列中的最小元素2
至此第三轮排序结束,比较次数为n - 3,时间复杂度为O(n)。
第三轮排序后,已排序序列更新为[1, 2, 2], 未排序序列为[5, 3],可以发现这里黑色加粗的2已经在未加粗的2后面了。

第四轮排序(i = 3): min = v[i] = 5
j = 4, min = 5 > v[j] = 3, 更新min = 3, index = 4
退出内层循环,最小值索引更新,交换当前位置元素5和未排序序列中的最小元素3。
至此第四轮排序结束,比较次数为n - 4, 时间复杂度为O(n)。
第四轮排序后,已排序序列更新为[1, 2, 2, 3,], 未排序序列更新为[5], 因为未排序序列中只有一个元素5了,所以无需再进行下一轮排序,即它已经是未排序序列中最小的元素了。直接放在已排序序列的末尾。

四轮排序过后排序完成,得到排序结果[1, 2, 2, 3, 5]。

时间复杂度

最好情况: 给定序列已经有序。

每轮排序最小值索引都没有更新,所以交换次数未0。但每轮排序都会进行比较,所以比较次数为(n - 1)+ (n - 2) + … 2 + 1 = n*(n-1)/2。

因此最好情况的总体时间复杂度为O(0) + O(n*(n-1)/2) = O(n2),即最好时间复杂度为O(n2)。

最坏情况: 给定序列逆序。

则每轮排序都会改变最小值索引,所以交换次数为n/2。每轮排序的比较次数依旧为n*(n-1)/2。

所以最坏的总体时间复杂度为O(n/2) + O(n*(n-1)/2) = O(n2),即最坏时间复杂度为O(n2)。

因此选择排序的平均复杂度为O(n2)

空间复杂度

因整个排序过程中我们只用到两个局部变量min和index,所以空间复杂度为O(1)。

选择排序算法的稳定性

排序算法的稳定性通俗地讲就是能保证排序前两个相等的数据其在序列中的先后位置顺序与排序后它们两个先后位置顺序相同。即:如,如果A i == A j,Ai 原来在 Aj 位置前,排序后 Ai 仍然是在 Aj 位置前。

在过程模拟的第三轮排序后,黑色加粗的2已经在未加粗的2后面了,其相对位置发生了改变,因此选择排序是不稳定的

和冒泡排序比较

最好情况下:给定序列有序
冒泡比较次数为n - 1,交换次数为0。选择比较次数为n*(n-1)/2, 交换次数为0。
冒泡好时间复杂度为O(n), 选择最好时间复杂度为O(n2)。

最坏情况下:给定序列逆序
冒泡比较次数为n*(n-1)/2, 交换次数为3n*(n-1)/2。选择比较次数为n*(n-1)/2,交换次数为n/2。
冒泡最坏时间复杂度为O(n2), 选择最坏时间复杂度为O(n2)。

冒泡是稳定排序,而选择是不稳定排序。

由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值