vlambda博客
学习文章列表

八大排序(二):简单选择排序






在上一篇开头已经介绍了排序的分类,如下图。



这次要介绍的是选择排序中的简单选择排序,可以看到堆排序也属于选择排序,不着急,会在后面的文章对它进行介绍。

选择排序

选择排序也是一种很简单的排序,没啥可以介绍的,直接看基本思想。

基本思想

假设对一个数组进行升序排序,第一次从arr[0] ~ arr[n-1]中选取出最小值,与arr[0]交换;第二次从arr[1] ~ arr[n-1]中选取出最小值,与arr[1]交换;… ;第i次从arr[i-1] ~ arr[n-1]中选取最小值,与arr[i-1]交换;… ;第n-1次(最后一次)从arr[n-2] ~ arr[n-1]中选取最小值,与arr[n-2]交换,总共通过n-1次选择交换操作,得到从小到大排列的有序序列。

虽然很简单,还是举个例子:对6、4、7、2进行升序排列
第1次:从6、4、7、2选择出最小值2,与6进行交换,得到2、4、7、6
第2次:从4、7、6选择出最小值4,与4进行交换(这里刚好重合了),得到2、4、7、6
第3次:从7、6选择出最小值6,与7进行交换,得到2、4、6、7,排序完毕

代码实现


public static void selectSort(int[] nums) { // 一共进行n-1次选择交换操作 for (int i = 0; i < nums.length - 1; i++) { // 用min来保存每一次比较得到的最小值的索引, // 假设当前最小值的下标是i int min = i; // 查找要操作的最小值 for (int j = i + 1; j < nums.length; j++) { min = nums[j] < nums[min] ? j : min; } // 如果i不是本次选择的最小元素,才进行交换 if (i != min) { int temp = nums[i]; nums[i] = nums[min]; nums[min] = temp; } }}

优化

每次查找最小值的同时也把最大值查找出来,这样迭代的次数就会减少一半。
代码如下:
public static void selectSort2(int[] nums) { for (int i = 0; i < nums.length / 2; i++) { // i是本次参与选择交换操作的元素中最左边端索引,right是最右端索引, // i的左边的元素和right的右边的元素都是已经排好序了的 int right = nums.length - i - 1; int min = i; int max = right;
for (int j = i + 1; j < nums.length - i; j++) { min = nums[j] < nums[min] ? j : min; max = nums[j] > nums[max] ? j : max; }
if (min != i) { int temp = nums[i]; nums[i] = nums[min]; nums[min] = temp; } if (max != right) { int temp = nums[right]; nums[right] = nums[max]; nums[max] = temp; } }}
注意:这种优化只能让性能得到些许提升,使得它大部分时间比不优化时快一点,并不能弥补它天生的性能问题。

时间复杂度

平均时间复杂度:O(n2
最好时间复杂度:O(n2
最坏时间复杂度:O(n2

性能测试

简单测试一下性能,代码如下:
numCount
耗时
10000
70ms
50000
1377ms
100000
5056ms
500000
99750ms
可以看到,它比冒泡排序快一些,但是当数据量达到五十万时,耗时100秒,还是很久了。虽然这些都是简单测试,并没有把硬件性能等因素加进去,但是也足以说明不同算法之间的性能问题了。

参见: