选择排序法
小例子
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,转载请注明。