前言
选择排序也是一个通过暴力遍历数组的简单排序算法,了解一下就行了~
手撕算法 - 排序系列
手撕面试题算法<排序>(1)—— 冒泡排序及其优化实现
手撕面试题算法<排序>(2)—— 选择排序
手撕面试题算法<排序>(3)—— 插入排序及其优化实现
手撕面试题算法<排序>(3.5)—— 希尔排序
手撕面试题算法<排序>(4)—— 归并排序
手撕面试题算法<排序>(5)—— 快速排序以及快排为什么快
手撕面试题算法<排序>(6)—— 堆 & 堆排序
手撕面试题算法<排序>(7)—— 箱排序 & 基数排序
源码
选择排序的思想
简单地说,选择排序的过程就是一次次地从一个无序数组中拿出它当前最小的元素,如,对数组[5,4,3,1,2]进行排序,过程如下:
排序次数 | 有序数组 | 无序数组 | 传入数组 |
---|---|---|---|
初始 | [] | [5,4,3,1,2] | [5,4,3,1,2] |
1 | [1] | [5,4,3,2] | [1,4,3,5,2] |
2 | [1,2] | [5,4,3] | [1,2,3,5,4] |
3 | [1,2,3] | [5,4] | [1,2,3,5,4] |
4 | [1,2,3,4] | [5] | [1,2,3,4,5] |
可以看出,每一趟排序只能遍历整个无序数组,选一个最小的来放在有序数组的末尾,非常的暴力,效率也不高,了解一下就行了~
时间复杂度
通过上面的过程,我们可以得到比较的过程为T = (n-1)+(n-2)+(n-3)+…+1 = (n-1)*n/2 => O(n2),无论在什么情况下都需要比较这么多次,所以最好/最坏情况的时间复杂度都是O(n2)
实现
public static void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; ++i) {
int minIdx = i;
// 在数组区间[i+1,j]中找出一个最小(比arr[i]还小的)的,记录其下标为minIdx
for (int j = arr.length - 1; j > i; --j) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
// 当minIdx发生变动,证明数组区间[i+1,j]中有比arr[i]小的值,进行交换
if (minIdx != i) {
// 交换数组arr中下标为i和minIdx的值
Swaper.exec(arr, i, minIdx);
}
}
}
这里交换方法为了省事我包装起来了,大家可以自己实现
测试
测试代码:
// 生成一个10000个元素的随机数组
int[] tmp = Tester.randomArr(10000);
int[] arr = tmp.clone();
System.out.println(Arrays.toString(arr));
long start = System.currentTimeMillis();
sort(arr);
long end = System.currentTimeMillis();
System.out.println("选择排序结束,耗时" + (end - start) + "ms");
System.out.println(Arrays.toString(arr));
结果:
虽然选择排序很暴力,但相对于冒泡排序来说,减少了swap的次数,还是比冒泡排序省时间的~