选择排序
选择排序算法的基本思路是为每一个位置选择当前最小的元素。选择排序的基本思想是,基于直接选择排序和堆排序这两种基本的简单排序方法。首先从第1个位置开始对全部元素进行选择,选出全部元素中最小的给该位置,再对第2个位置进行选择,在剩余元素中选择最小的给该位置即可,以此类推。
选择排序图解
原理及思路
每次循环时在待排序列中找出最小值,将其与待排序列头元素进行交换
- 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,
- 然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。
- 以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
排序的效率
- 时间复杂度:O(n^2)
- 空间复杂度:O(1) -> 未新开辟内存
算法稳定性
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
选择排序的优化
每次循环时在待排序列中找出最小值和最大值,将最小值与左下标进行交换,将最大值与右下标进行交换。
此处的优化仅仅减少了在找值的时候的次数,对整体时间复杂度没有影响
代码实现
private static <T> void swap(T[] arr,int index1,int index2){
T temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
//一般性选择排序,只在序列中找最小值
public static <T extends Comparable<T>> void selectSort(T[] arr){
if(arr == null || arr.length == 0 || arr.length == 1){
return;
}
//遍历整个数组
for(int i = 0;i < arr.length;i++){
//定义最小值下标为待排序列头元素下标
int minIndex = i;
//进行判断更换最小值下标
for(int j = i;j < arr.length;j++){
//如果遇到比目前最小值下标元素还小的进行更新最小值下标
if(arr[minIndex].compareTo(arr[j]) > 0){
minIndex = j;
}
}
//将其值与待排序列头元素进行交换
swap(arr,minIndex,i);
}
}
//优化性选择排序,在序列中寻找最小值和最大值
public static <T extends Comparable<T>> void selectSortToOptimize(T[] arr){
if(arr == null || arr.length == 0 || arr.length == 1){
return;
}
//定义左下标和右下标
int left = 0,right = arr.length - 1;
while (left < right) {
//初始化最小值下标和最大值下标
int minIndex = left,maxIndex = left;
//遍历待排序列进行找值
for (int i = left; i <= right; i++) {
//如果遇到比目前最小值下标元素还小的进行更新最小值下标
if(arr[minIndex].compareTo(arr[i]) > 0){
minIndex = i;
}
//如果遇到比目前最大值下标元素还大的进行更新最大值下标
if(arr[maxIndex].compareTo(arr[i]) < 0){
maxIndex = i;
}
}
//此处进行数据交换
//注意特殊情况
//如果最大值下标在左下标处,最小值下标在右下标处,直接交换最小值下标和最大值下标元素
if(minIndex == right && maxIndex == left){
swap(arr,minIndex,maxIndex);
}else {
//否则将最小值与左下标进行交换,将最大值与右下标进行交换
swap(arr, minIndex, left);
//此处存在另一种特殊情况
// -> 如果最大值下标在左下标处或者最小值下标在右下标处,有可能进行重复交换,所以进行判断
if(arr[minIndex].compareTo(arr[maxIndex]) < 0) {
swap(arr, maxIndex, right);
}
}
//更新左下标和右下标
left++;right--;
}
}