【排序算法】选择排序

284 阅读2分钟

选择排序

选择排序,一般我们指的是简单选择排序,你可以叫直接选择排序,他不是像冒泡排序一样相邻交换元素,而是通过选择一轮元素中最小的元素,进行交换,虽然交换次数少,但是效率和冒泡排序一样糟糕!

选择排序属于选择类排序算法

算法介绍

🌰:5 9 1 6 8 14 6 49 25 4 6 3

GIF 2021-12-23 10-47-51

注:

  • 橙色表示已完成排序的元素
  • 红色表示标记当前(最小/需要交换)元素
  • 绿色表示扫描元素

这个排序过程很好理解:

  • 第一轮迭代,从第一个数开始,从左边向右边进行扫描,找到最小的数,与第一个数进行交换
  • 第二轮迭代,从第二个数开始,从左边到右边进行扫描,找到最小的数,与第二个数进行交换
  • N 轮迭代:…

最后是可以得到结果:1 3 4 5 6 6 6 8 9 14 25 49

上述的行为叫做简单选择排序。

选择排序是一个不稳定的排序算法,比如数组:[5 6 5 1],第一轮迭代时最小的数是 1,那么与第一个元素 5 交换位置,这样数字 1 就和数字 5 交换了位置,导致两个相同的数字 5 排序后位置变了。

时间复杂度

他每一轮的比较次数和冒泡排序是一样的,不同的是,他的每轮迭代交换次数减少到了 1 次。

总体的比较次数:1+2+3+4+...+N-1=(N^2 - N)/2,这是平方级别的时间复杂度,我们记为 O(n^2)

空间复杂度

只用到了一个变量,所以是常量:O(1)

算法实现

func SelectSort(list []int)  {
	//第一层循环遍历每一轮需要交换的值
	for i:=0;i<len(list);i++{
		//记录最小元素的索引位置
		minIndex :=i
		//第二层循环扫描,获取最小的元素
		for j:=i+1;j<len(list);j++{
			//记录最小元素的索引
			if list[j]<list[minIndex ]{
				minIndex =j
			}
		}
		//交换
		list[i],list[minIndex ]=list[minIndex ],list[i]
	}
}

其实整体上这个算法比较好懂的一个。

算法改进

func SelectSortPro(list []int)  {
	n:=len(list)
	//第一层遍历 n/2 次数
	for i:=0;i<n/2;i++{
		//每一轮最小值的索引
		minIndex:=i
		//每一轮最大值索引
		maxIndex:=i
		//找到这一轮的最大值与最小值
		for j:=i+1;j<n-i;j++{
			if list[j]>list[maxIndex]{
				maxIndex=j
			}
			if list[j]<list[minIndex]{
				minIndex=j
			}
		}
		//为什么不能直接允许下面的代码
		//list[i],list[minIndex]=list[minIndex],list[i]
		//list[n-i-1],list[maxIndex]=list[maxIndex],list[n-i-1]
		/*
		因为存在最大值在开头,如果你先最小值与开头值进行交换,就会把最大值换一个位置,导致最后无法交换正确
		最小值一样,所以这里是有一定交换顺序的。
		当最大值在开头处,应该先换最大值。
		当最小值在结尾处,应该先换最小值。
		当最小值在结尾,最大值在开头,两次交换会导致交换无效
		其余情况顺序其实就无所谓了。
		*/
		if maxIndex==i&&minIndex!=n-i-1{
			list[n-i-1],list[maxIndex]=list[maxIndex],list[n-i-1]
			list[i],list[minIndex]=list[minIndex],list[i]
		}else if maxIndex==i&&minIndex==n-i-1{
			list[maxIndex],list[minIndex]=list[minIndex],list[maxIndex]
		}else {
			list[i],list[minIndex]=list[minIndex],list[i]
			list[n-i-1],list[maxIndex]=list[maxIndex],list[n-i-1]
		}
	}
}

选择算法还是比较慢的,好理解,但是不建议选择使用。

参考