选择排序
1. 算法概述
选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
2. 算法原理
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
- 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
- 重复第二步,直到所有元素均排序完毕。
3. 动图演示
4. 代码实现
@Test
public void sort() {
int[] arr = new int[]{2, 7, 1, 4, 5, 3, 6};
//从第一个开始,到最后一个,进行比较,总共能够执行 n - 1 次
//每一趟执行完成后,都会选出一个相对最小的元素,排在已经排序好的元素后面
for (int i = 0; i < arr.length - 1; i++) {
//临时存储索引
int min = i;
//与之后的所有元素进行对比,然后选出一个相对最小的元素
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[min]) {
// 记录目前能找到的最小值元素的索引
min = j;
}
}
// 将找到的最小值和i位置所在的值进行交换
if (i != min) {
swap(arr, min, i);
}
}
log.info("排序后:{}", JSON.toJSONString(arr));
}
5. 算法优化
对于每一趟,我们需要遍历一遍,将找到的最小的数放在应该出现的位置,所以,选择排序的时间复杂度是O(n²),不管是最好情况还是最坏情况,找最小数的过程都需要遍历一遍,所以,选择排序最好情况也是O(n²)。
优化方案:根据上边的分析,如果在每一次查找最小值的时候,也可以找到一个最大值,然后将两者分别放在它们应该出现的位置,这样遍历的次数就比较少了一半,下边给出代码实现:
@Test
public void sort1() {
int[] arr = new int[]{1, 2, 7, 1, 4, 5, 3, 6};
//左侧开始排序相对最小值,相对第一个下表,默认为0
int left = 0;
//右侧开始排序相对最大值,相对第一个坐标,默认为arr.length - 1
int right = arr.length - 1;
while (left < right) {
//记录无序区最大元素下标、最小元素下标
int max = left, min = left;
//临时变量,记录当前操作元素的下标
int temp = 0;
//temp = left + 1 表示 <= left 已经排好序,在有序元素后一位开始,与最后一个有序元素对比
//temp <= right 表示 >= right 已经排好序,不能超过该位置
for (temp = left + 1; temp <= right; temp++) {
//找最大元素下标
if (arr[temp] < arr[min]) {
min = temp;
}
//找最小元素下标
if (arr[temp] > arr[max]) {
max = temp;
}
}
//min == left 则表示,本次找到的最小值就是当前位置,则没有必要交换
if (min != left) {
swap(arr, left, min);
//【注意】如果最大元素是left, 上一步已经将 最小元素min 交换到 left位置,此时 min下标存储的是原left的元素
if (max == left) {
max = min;
}
}
//max == right 则表示,本次找到的最大值就是当前位置,则没有必要交换
if (max != right) {
swap(arr, max, right);
}
//左右两侧指针向中间移动
left++;
right--;
}
log.info("排序后:{}", JSON.toJSONString(arr));
}