选择排序法
小例子
package SelectionSort;
public class SelectionSort {
private SelectionSort() {
}
public static void sort(int[] arr) {
// arr[0...i) 是有序的;arr[i...n) 是无序的
for (int i = 0; i < arr.length; i++) {
// 选择 arr[i。。。n) 中的最小值索引
int minIndex = i;
for (int j = i; j < arr.length; j++) {
if (arr[j] < arr[minIndex])
minIndex = j;
}
swap(arr, i, minIndex);
}
}
private static void swap(int[] arr, int i, int j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
public static void main(String[] args) {
int[] arr = {1, 4, 2, 3, 6, 5};
SelectionSort.sort(arr);
for (int e : arr)
System.out.print(e + " ");
System.out.println();
}
}
控制台输出
1 2 3 4 5 6
修改排序算法小例子为泛型
避免篇幅过长,这里仅给出关键代码
//对泛型进行约束
public static <E extends Comparable<E>> void sort(E[] arr) {
// arr[0...i) 是有序的;arr[i...n) 是无序的
for (int i = 0; i < arr.length; i++) {
// 选择 arr[i。。。n) 中的最小值索引
int minIndex = i;
for (int j = i; j < arr.length; j++) {
if (arr[j].compareTo(arr[minIndex])< 0 ) // < 就是<0 >就是>0 这个简单的操作一定要知道
minIndex = j;
}
swap(arr, i, minIndex);
}
} private static <E> void swap(E[] arr, int i, int j) {
E t = arr[i];
arr[i] = arr[j];
arr[j] = t;
} Integer[] arr = {1, 4, 2, 3, 6, 5};
SelectionSort.sort(arr); 使用compareTo接口
在学习之前,我们先重点要知道一个思想,这个也是我首页设计模式的类似思想,这里会有一些体现:
我们的排序算法不关心你是如何实现的,你的具体如何实现,我们通常是由类的设计者来实现!
老规矩,我们一个自定义的student类,里面重写的是compareTo的对比方法,具体思想是我们对比学生的学习成绩来进行排序
package SelectionSort;
public class Student implements Comparable<Student>{
private String name;
private int score;
public Student(String name,int score) {
this.name = name;
this.score = score;
}
@Override
public boolean equals(Object student){
if (this==student)
return true;
if (student==null)
return false;
if (this.getClass() != student.getClass())
return false;
Student another = (Student) student;
return this.name.toLowerCase().equals(another.name.toLowerCase());
}
@Override
public int compareTo(Student another) {
// if (this.score < another.score)
// return -1;
// else if (this.score == another.score)
// return 0;
// return 1;
return this.score - another.score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
我们直接看main方法的具体使用
public static void main(String[] args) {
Student[] students = {new Student("白萝卜", 100),
new Student("大白菜", 99),
new Student("小马哥", 78)};
SelectionSort.sort(students);
for (Student student:students){
System.out.println(student);
}
} Student{name='小马哥', score=78} 控制台输出
Student{name='大白菜', score=99}
Student{name='白萝卜', score=100}
前面我们是从小到大排序,我们如果想改造成从大到小怎么操作呢?
return this.score - another.score;
上面小例子的排序复杂度分析
public static void main(String[] args) {
//0.064107 s
int[] dataSize = {10000, 100000};
for(int n: dataSize){
Integer[] arr = ArrayGenerator.generateRandomArray(n, n);
SortingHelper.sortTest("SelectionSort", arr);
}
} 随机生成数组内容
package SelectionSort;
import java.util.Random;
public class ArrayGenerator {
private ArrayGenerator(){}
public static Integer[] generateOrderedArray(int n){
Integer[] arr = new Integer[n];
for(int i = 0; i < n; i ++)
arr[i] = i;
return arr;
}
// 生成一个长度为 n 的随机数组,每个数字的范围是 [0, bound)
public static Integer[] generateRandomArray(int n, int bound){
Integer[] arr = new Integer[n];
Random rnd = new Random();
for(int i = 0; i < n; i ++)
arr[i] = rnd.nextInt(bound);
return arr;
}
}
校验是否完成排序
public class SortingHelper {
private SortingHelper(){}
public static <E extends Comparable<E>> boolean isSorted(E[] arr){
for(int i = 1; i < arr.length; i ++)
if(arr[i - 1].compareTo(arr[i]) > 0)
return false;
return true;
}
public static <E extends Comparable<E>> void sortTest(String sortname, E[] arr){
long startTime = System.nanoTime();
if(sortname.equals("SelectionSort"))
SelectionSort.sort(arr);
long endTime = System.nanoTime();
double time = (endTime - startTime) / 1000000000.0;
if(!SortingHelper.isSorted(arr))
throw new RuntimeException(sortname + " failed");
System.out.println(String.format("%s , n = %d : %f s", sortname, arr.length, time));
}
}
控制台输出
SelectionSort , n = 10000 : 0.067416 s
SelectionSort , n = 100000 : 8.220553 s
我们之前是从数组的最前面开始排序,那我们能不能从最后面开始排序呢?
public static <E extends Comparable<E>> void sort2(E[] arr) {
// arr[0...i) 是有序的;arr[i...n) 是无序的
for (int i = arr.length-1; i > 0; i--) {
// 选择 arr(0。。。i] 中的最小值索引
int minIndex = i;
for (int j = i; j >=0; j--) {
if (arr[j].compareTo(arr[minIndex]) > 0) // < 就是<0 >就是>0 这个简单的操作一定要知道
minIndex = j;
}
swap(arr, i, minIndex);
}
} 插入排序法
package InsertionSort;
public class InsertionSort {
private InsertionSort() {
}
public static <E extends Comparable<E>> void sort(E[] arr) {
for (int i = 0; i < arr.length; i++) {
//将 arr[i] 插入到合适的位置
for (int j = i; j - 1 >= 0; j--) {
if (arr[j].compareTo(arr[j - 1]) < 0) {
swap(arr, j, j - 1);
} else {
break;
}
}
}
}
/**
* 简单的数组元素交换
*
* @param arr
* @param i
* @param j
* @param <E>
*/
private static <E> void swap(E[] arr, int i, int j) {
E t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
public static void main(String[] args) {
Integer[] date = {1,2,2,85,7,6,5};
sort(date);
for (int e:date){
System.out.println(e);
}
}
}
这里代码也可以再升级,会看起来比较简洁,但是逻辑不是很清晰,时间基本一样,看个人喜欢
public static <E extends Comparable<E>> void sort(E[] arr) {
for (int i = 0; i < arr.length; i++) {
//将 arr[i] 插入到合适的位置
// for (int j = i; j - 1 >= 0; j--) {
// if (arr[j].compareTo(arr[j - 1]) < 0) {
// swap(arr, j, j - 1);
// } else {
// break;
// }
// }
//升级代码
for (int j = i; j - 1 >= 0 && arr[j].compareTo(arr[j - 1]) < 0; j--) {
swap(arr, j, j - 1);
}
}
} 插入排序算法的小优化
public static <E extends Comparable<E>> void sort2(E[] arr) {
for (int i = 0; i < arr.length; i++) {
//将 arr[i] 插入到合适的位置
E t = arr[i];
int j;
for (j = i; j - 1 >= 0 && t.compareTo(arr[j - 1]) < 0; j--) {
arr[j] = arr[j-1];
}
arr[j] = t;
}
} 插入排序法的重要特性
本文作者为DBC,转载请注明。


