选择排序(Selectionsort)是一种简单直观的排序算法。
时间复杂度(o^2)
(他是不稳定的:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面)
它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
arr={3,2,5,4,1}
我们来看一个这几个数用选择排序的过程是什么样的吧,我这里就按从小到大的顺序排序
(1)首先假定数组第一个元素就是最小的,将他的值和后面的进行比较,如果有比他还要小的数, 就暂时把这个数的值视为最小的,然后一直比较到最后一个,我们记录下这一趟下来最小的数的值以及索引,与数组第一个元素交换他们的值以及索引
1 , 2 , 5 , 4 , 3
(2)从第二次开始,我们就上一次的结果出发,假设未排序的序列中第一个元素就是最小的,和后面的进行比较,如果有比他还要小的数,就暂时把这个数的值视为最小的,然后一直比较到最后一个,我们记录下这一趟下来最小的数的值以及索引,与未排序的序列的第一个元素交换他们的值以及索引
1 , 2 , 5 , 4 , 3
(3)
1 , 2 , 3 , 4 , 5
(4)
1 , 2 , 3 , 4 , 5
我现在来实现一下每趟循环是怎样的:
(主要是看一下前两趟的)
import java.util.Arrays;
public class SortTest2 {
public static void main(String[] args) {
int arr[]={3,2,5,4,1};
/**
首先假设第一个元素就是最小的,我们取出它的值以及索引
这么做还有一个目的就是:选择排序一次就交换最小值和假定最小值的位置,所以只能靠值传递
可能刚开始会想到冒泡排序那种写法
那是没有注意到,冒泡是每比较一次就啃发生交换,根本不符合选择排序的一趟只是发生一次交换
的需求
*/
int minIndex=0;
int min=arr[0];
//我们要拿后面的元素和假定最小的元素进行比较
for(int j=0+1;j<arr.length;j++){
if(min>arr[j]){
min=arr[j];
minIndex=j;
}
}
//真正发生交换的地方在这里,我们上面已经找到了真正的最小值
//交换数组第一个元素和这个最小值的位置
arr[minIndex] = arr[0];
arr[0] = min;
System.out.println("这是选择排序的第一趟:"+Arrays.toString(arr));
minIndex=1;
min=arr[1];
//我们要拿后面的元素和假定最小的元素进行比较
for(int j=1+1;j<arr.length;j++){
if(min>arr[j]){
min=arr[j];
minIndex=j;
}
}
if(minIndex!=1){
//我们发现最小值其实就是a[1],他的位置没有发生改变,所以没有必要进行交换
//所以加上了一个判断,看看假定最小值的索引和真正最小值的索引是不是相同
arr[minIndex]=arr[1];
arr[1]=min;
}
System.out.println("这是选择排序的第二趟:"+Arrays.toString(arr));
}
}
最终版本:
import java.util.Arrays;
public class SelectSort {
public void sort(int arr[]){
for(int i=0;i<arr.length-1;i++){
//我们这里拿min值和后面的数比较,最终只是交换了最小值和假定最小值的位置
int min=arr[i];
int minindex=i;
for(int j=i+1;j<arr.length;j++){
if(min>arr[j]){
minindex=j;
min=arr[j];
}
}
//还有就是选择排序一次只是交换了最小值和假定最小值的位置
//所以我把交换的步骤写在了内循环的外面,写在里面的话,虽然最后结果是一样的
//但是他中间交换了多次数组第一个元素的位置,是不符合原理的
if(minindex!=i) {
arr[minindex] = arr[i];
arr[i] = min;
}
}
System.out.println("这是选择排序后的结果"+ Arrays.toString(arr));
}
}
public class run(){
public static void main(String[] args) {
SelectSort selectSort = new SelectSort();
int arr[]={2,5,4,1,3};
selectSort.sort(arr);
}
}
最后来看一下执行的时间,选择还是和上篇文章中一样,80000大小的数组,用随机数范围是(0,1]*800000,
public static void main(String[] args) {
SelectSort selectSort = new SelectSort();
int arr2[]=new int[80000];
for(int i=0;i<80000;i++){
arr2[i]=(int)(Math.random()*8000000);
}
Date date1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date1);
System.out.println("排序前的时间"+format);
selectSort.sort(arr2);
Date date2 = new Date();
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format2 = simpleDateFormat2.format(date2);
System.out.println("排序后的时间"+format2);
selectSort.sort(arr);
}
执行时间是2~3秒,比冒泡排序10-11s的快很多