首先构建测试函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 public class SortTestHelper { private SortTestHelper () {} public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) { assert rangeL <= rangeR; Integer[] arr = new Integer[n]; for (int i = 0 ; i < n; i++) arr[i] = new Integer((int )(Math.random() * (rangeR - rangeL + 1 ) + rangeL)); return arr; } public static void printArray (Object arr[]) { for (int i = 0 ; i < arr.length; i++){ System.out.print( arr[i] ); System.out.print( ' ' ); } System.out.println(); return ; } public static boolean isSorted (Comparable[] arr) { for ( int i = 0 ; i < arr.length - 1 ; i ++ ) if ( arr[i].compareTo(arr[i+1 ]) > 0 ) return false ; return true ; } public static void testSort (String sortClassName, Comparable[] arr) { try { Class sortClass = Class.forName(sortClassName); Method sortMethod = sortClass.getMethod("sort" ,new Class[]{Comparable[].class }) ; Object[] params = new Object[]{arr}; long startTime = System.currentTimeMillis(); sortMethod.invoke(null ,params); long endTime = System.currentTimeMillis(); assert isSorted ( arr ) ; System.out.println( sortClass.getSimpleName()+ " : " + (endTime-startTime) + "ms" ); } catch (Exception e){ e.printStackTrace(); } } } }
排序时间复杂度最优的是nlogn,首先接触on^2^的算法,编码简单,易于实现,是一些简单情景的首选.在一些特殊情况下,简单的排序算法更有效
一、选择排序Select Sort 第一次遍历1-n个元素,选出最小元素的和第一位元素交换(这个交换可能进行了多次),第二次遍历第2-n个元素,选出最小的和第二位元素交换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class SelectionSort { private SelectionSort () {} public static void sort (Comparable[] arr) { int n = arr.length; for ( int i = 0 ; i < n ; i ++ ){ int minIndex = i; for ( int j = i + 1 ; j < n ; j ++ ) if ( arr[j].compareTo( arr[minIndex] ) < 0 ) minIndex = j; swap( arr , i , minIndex); } } private static void swap (Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; }
二、插入排序InsertionSort
除了第一个元素之外,从第二个元素开始,若是比前一个元素大就交换,反复进行,直到比前一个元素小的时候停止
插入排序第一段代码由于交换操作非常多会影响算法的速度
改进后,先将目标位置的元素值保存,再将目标位置的元素与前面的元素比较,若是比前一个元素大就将前一个元素值赋给它,再将原来的值与更往前的一个元素比较,并持续将后一个元素的值赋给前一个,直到比某一个元素小的时候停止,并将之前保存的值插入这个位置
插入排序在本来排列就较为有序的数组排序效率很高,因为第二层循环j > 0 && arr[j].compareTo(arr[j-1]) < 0 可能会提前结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class InsertionSort { private InsertionSort () {} public static void sort (Comparable[] arr) { int n = arr.length; for (int i = 0 ; i < n; i++) { for ( int j = i; j > 0 && arr[j].compareTo(arr[j-1 ]) < 0 ; j--) swap(arr, j, j-1 ); } } private static void swap (Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } public static void main (String[] args) { int N = 20000 ; Integer[] arr = SortTestHelper.generateRandomArray(N, 0 , 100000 ); SortTestHelper.testSort("bobo.algo.InsertionSort" , arr); return ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.*;public class InsertionSort { private InsertionSort () {} public static void sort (Comparable[] arr) { int n = arr.length; for (int i = 0 ; i < n; i++) { Comparable e = arr[i]; int j = i; for ( ; j > 0 && arr[j-1 ].compareTo(e) > 0 ; j--) arr[j] = arr[j-1 ]; arr[j] = e; } } private static void swap (Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
三、 冒泡排序BubbleSort 将相邻两个元素不断交换,将最大值冒泡到顶部(第n位),再重复这一过程,将次大的值,冒泡到n-1位,直到只剩一个元素。
时间复杂度 On^2^
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.Arrays;public class BubbleSort { private BubbleSort () {} public static void sort (Comparable[] arr) { int n = arr.length; boolean swapped = false ; do { swapped = false ; for ( int i = 1 ; i < n ; i ++ ) if ( arr[i-1 ].compareTo(arr[i]) > 0 ){ swap( arr , i-1 , i ); swapped = true ; } n --; }while (swapped); } private static void swap (Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
四、希尔排序 没看懂 是插入排序的延伸
复杂度n^3/2^
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class ShellSort { private ShellSort () {} public static void sort (Comparable[] arr) { int n = arr.length; int h = 1 ; while (h < n/3 ) h = 3 *h + 1 ; while (h >= 1 ) { for (int i = h; i < n; i++) { Comparable e = arr[i]; int j = i; for ( ; j >= h && e.compareTo(arr[j-h]) < 0 ; j -= h) arr[j] = arr[j-h]; arr[j] = e; } h /= 3 ; } } }
五、归并排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 import java.util.*;public class MergeSort { private MergeSort () {} private static void merge (Comparable[] arr, int l, int mid, int r) { Comparable[] aux = Arrays.copyOfRange(arr, l, r+1 ); int i = l, j = mid+1 ; for ( int k = l ; k <= r; k ++ ){ if ( i > mid ){ arr[k] = aux[j-l]; j ++; } else if ( j > r ){ arr[k] = aux[i-l]; i ++; } else if ( aux[i-l].compareTo(aux[j-l]) < 0 ){ arr[k] = aux[i-l]; i ++; } else { arr[k] = aux[j-l]; j ++; } } } private static void sort (Comparable[] arr, int l, int r) { if ( r - l <= 15 ){ InsertionSort.sort(arr, l, r); return ; } int mid = (l+r)/2 ; sort(arr, l, mid); sort(arr, mid + 1 , r); if ( arr[mid].compareTo(arr[mid+1 ]) > 0 ) merge(arr, l, mid, r); } public static void sort (Comparable[] arr) { int n = arr.length; sort(arr, 0 , n-1 ); } }
还可以使用自底向下的非递归方法实现,好处是没有使用数组索引,可以契合链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import java.util.*;public class MergeSortBU { private MergeSortBU () {} private static void merge (Comparable[] arr, int l, int mid, int r) { Comparable[] aux = Arrays.copyOfRange(arr, l, r+1 ); int i = l, j = mid+1 ; for ( int k = l ; k <= r; k ++ ){ if ( i > mid ){ arr[k] = aux[j-l]; j ++; } else if ( j > r ){ arr[k] = aux[i-l]; i ++; } else if ( aux[i-l].compareTo(aux[j-l]) < 0 ){ arr[k] = aux[i-l]; i ++; } else { arr[k] = aux[j-l]; j ++; } } } public static void sort (Comparable[] arr) { int n = arr.length; for ( int i = 0 ; i < n ; i += 16 ) InsertionSort.sort(arr, i, Math.min(i+15 , n-1 ) ); for ( int sz = 16 ; sz < n ; sz += sz ) for ( int i = 0 ; i < n - sz ; i += sz+sz ) if ( arr[i+sz-1 ].compareTo(arr[i+sz]) > 0 ) merge(arr, i, i+sz-1 , Math.min(i+sz+sz-1 ,n-1 ) ); } }
六、快速排序 通过partition过程,找到第一个元素应该放入的位置,在这个位置前的元素都小于它,在他之后的元素都大于他,并不断递归这个过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import java.util.*;public class QuickSort { private QuickSort () {} private static int partition (Comparable[] arr, int l, int r) { Comparable v = arr[l]; int j = l; for ( int i = l + 1 ; i <= r ; i ++ ) if ( arr[i].compareTo(v) < 0 ){ j ++; swap(arr, j, i); } swap(arr, l, j); return j; } private static void sort (Comparable[] arr, int l, int r) { if ( l >= r ) return ; int p = partition(arr, l, r); sort(arr, l, p-1 ); sort(arr, p+1 , r); } public static void sort (Comparable[] arr) { int n = arr.length; sort(arr, 0 , n-1 ); } private static void swap (Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }