一、基本原理
选择排序的基本原理为,将数组分成已排序和待排序的两部分,初始时已排序部分没有元素,数组的所有元素均在未排序部分中([0 ... arr.length-1])。每一轮从待排序的元素中选出一个最大元素放到已排序序列中,直到待排序部分为空或只有一个元素。具体来说,选择排序就是利用下标的大小,在每一轮中将剩余元素的最大值放在待排序序列的最大下标处,让待排序序列的边界减1。
选择排序其实就是在冒泡排序每一轮的每一轮遍历中维护一个最大值变量指向最大值,从而减少相邻元素的交换操作,最后将待排序序列最大下标处的元素与之交换。由于交换时后面的元素可能被交换到与之相同的元素之前的位置,所以选择排序是不稳定排序。
二、代码实现
public class Sort {
//选择排序
public static void selectionSort(int[] arr) {
for (int i=0; i<arr.length-1; i++) { //控制遍历的轮数
int max = 0;
for (int j=0; j<=arr.length-i-1; j++) { //未排序范围:[0, arr.length-i-1]
if (arr[j] >= arr[max]) {
max = j;
}
}
//每一轮交换一次
swap(arr, max, arr.length-i-1);
}
}
private static void swap(int[] arr, int i, int j) {
if (i == j) {
//无需交换
return;
}
arr[i] = arr[i] + arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j];
}
}
虽然上面说的是选择排序是不稳定排序,但其实它也可以改成稳定排序版本。原始版本的选择排序之所以是不稳定的,是因为每一轮最后的交换操作,那么如果能做到不用交换就可以将该轮的最大值放在最后的位置,自然就可以做到稳定排序了。具体的做法是,将交换操作改为将最小元素之后的所有未排序元素往前移动一位,再将最小元素放在腾出来的位置。
public class Sort {
//稳定版本的选择排序
public static void selectionSort1(int[] arr) {
for (int i=0; i<arr.length-1; i++) { //控制遍历的轮数
int max = 0;
for (int j=0; j<=arr.length-i-1; j++) { //未排序范围:[0, arr.length-i-1]
if (arr[j] >= arr[max]) { //如果取当前最大值,则应该找最后一个max(有重复的情况下);
//如果取当前最小值,则应该找第一个min(采用下面没有等号的判断形式)
//if (arr[j] > arr[max]) {
max = j;
}
}
//每一轮交换一次
//swap(arr, max, arr.length-i-1);
//
//每一轮移动一次元素
int temp = arr[max];
for (int j=max; j<arr.length-i-1; j++) {
arr[j] = arr[j+1];
}
arr[arr.length-i-1] = temp;
}
}
}
参考:
https://baike.baidu.com/item/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F/9762418?fr=aladdin