简介
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法
选择排序相较于冒泡排序,选择排序中进行数据的交换进行了减少,因此效率会有所上升。
为什么选择排序是不稳定的?
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。举个例子,序列4 8 4 2 9,我们知道第一遍选择第1个元素4会和2交换,那么原序列中两个4的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
简单来说就是排序过后那两个4的前后位置可能会发生改变。
选择排序的思路
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
代码实现
public class SelectionSort {
//选择排序
public static void main(String[] args) {
//自定义一个数组并赋值
int[] arr = {3, 2, 1, 3, 6, 7, 8, 9};
//调用方法排序
selectionSort(arr);
//遍历输出
for (int i : arr) {
System.out.print(" " + i);
}
}
public static void selectionSort(int[] nums) {
//从小到大排序
for (int i = 0; i < nums.length - 1; i++) {
//存储起始位下标
int min = i;
for (int j = i+1; j < nums.length; j++) {
//判断数据大小,找到最小值的下标
if (nums[min] > nums[j]) {
min = j;
}
}
//把最小值和起始位的值进行交换
int temp = nums[i];
nums[i] = nums[min];
nums[min] = temp;
}
}
}
上面代码实现的就是用基本的选择排序进行数据处理,外层循环少一次的原因就是当最后排序只剩下一个的时候,那么这个数肯定就是排序规则的最值了。所以可以少循环一次。
代码优化
在各种排序算法中,有多种不同的优化,在不同场景也要用不同的优化方案以及不同的排序算法,下面是我对于选择排序的一个小优化,优化方式就是当数据达到某种特殊状态时已经排好序了,那么就不用进行接下来的循环了。如何判断数据是否排好序了呢?
我们从代码中可以看出,我们把内层循环每次遍历的起始位在外层循环中记录了下来,在内层循环中当满足if判断条件时会进行下标数据从新赋值,记录新的较小值的下标,直到内层循环遍历结束,确定新最小值的下标,进行数据交换。
所以我们可不可以这样去思考,就是内层循环的条件没有达成过,也就是记录下标的变量的值没有变过,那就表示没有数据要交换,所以可以在if判断里面添加个哨兵,用来判断是否需要进行最值的位置交换。
第二种思想:既然一次外循环可判断出最小值,那是不是也就可以判断出最大值。所以我们可以在内层循环里面把最大值也判断出来。
下面是第二种思想的实现:
public class SelectionSort {
//选择排序
public static void main(String[] args) {
//自定义一个数组并赋值
int[] arr = {3, 2, 1, 3, 6, 7, 8, 9};
//调用方法排序
selectionSort2(arr);
//遍历输出
for (int i : arr) {
System.out.print(" " + i);
}
}
public static void selectionSort(int[] nums) {
//从小到大排序
for (int i = 0; i < nums.length - 1; i++) {
//存储起始位下标
int min = i;
for (int j = i + 1; j < nums.length; j++) {
//判断数据大小,找到最小值的下标
if (nums[min] > nums[j]) {
min = j;
}
}
//把最小值和起始位的值进行交换
int temp = nums[i];
nums[i] = nums[min];
nums[min] = temp;
}
}
//优化选择排序
public static void selectionSort2(int[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
int maxIndex = i;//假定最大值的下标
int max = arr[i];//假定最大值
int minIndex = arr.length - 1 - i;
int min = arr[minIndex];
for (int j = i; j < arr.length - i; j++) {//循环找到最大值
if (max < arr[j]) {// 说明假定的值不是最大的
max = arr[j];// 重置max
maxIndex = j;// 重置maxIndex
}
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
}
// 数据交换
int temp1 = arr[maxIndex];
int temp2 = arr[minIndex];
arr[maxIndex] = arr[arr.length - i - 1];
arr[arr.length - i - 1] = temp1;
arr[minIndex] = arr[i];
arr[i] = temp2;
}
}
}
总结
总而言之,言而总之,我的理解就是在冒泡排序的思想上,不进行多次的数据交换了,一次外循环直接找出最值,然后放在它该呆的位置。还是比较好理解的。看过后感觉有点点触动就留下个赞赞吧!加油!!!