算法系列(三)插入排序的兩種改進:規避邊界檢測和取消交換(Java實現)
阿新 • • 發佈:2019-01-29
前言:演算法第四版習題2.1.24插入排序的哨兵和習題2.1.25不需要交換的插入排序
規避邊界檢測:
在插入排序的實現中先找到最小的元素並將其置於陣列的第一個位置,可以省掉內迴圈的判斷條件 j>0 。能夠省略判斷條件的元素稱為哨兵。
不需要交換:public class Exer24 { public static void sort(Comparable[] a){ int N = a.length; for (int i = N-1; i > 0; i--) { if(less(a[i],a[i-1])) exch(a,i,i-1); } for (int i = 2; i < N; i++) { for (int j = i; /*j > 0 && */less(a[j],a[j-1]); j--) { exch(a,j,j-1); } } } private static boolean less(Comparable v, Comparable w){ //比較v是否小於w return v.compareTo(w) < 0; } private static void exch(Comparable[] a, int i, int j) { //交換 Comparable t = a[i]; a[i] = a[j]; a[j] = t; } public static void show(Comparable[] a){ //單行列印陣列 for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } System.out.println(); } public static boolean isSorted(Comparable[] a){ //判斷是否有序 for (int i = 1; i < a.length; i++) { if(less(a[i], a[i-1])) return false; } return true; } }
使較大元素右移一位只需要訪問一次陣列,而使用交換需要訪問兩次。
總結:寫出正確的演算法是首要的,改進是第二步。通過簡單的程式碼改進演算法的效率是一種優雅的行為。public class Exer25 { public static void sort(Comparable[] a){ int N = a.length; for (int i = 2; i < N; i++) { Comparable t = a[i]; int j = i; for (; j > 0 && less(t, a[j-1]); j--) { a[j] = a[j-1]; //大的右移 } a[j] = t; } } private static boolean less(Comparable v, Comparable w){ //比較v是否小於w return v.compareTo(w) < 0; } private static void exch(Comparable[] a, int i, int j) { //交換 Comparable t = a[i]; a[i] = a[j]; a[j] = t; } public static void show(Comparable[] a){ //單行列印陣列 for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } System.out.println(); } public static boolean isSorted(Comparable[] a){ //判斷是否有序 for (int i = 1; i < a.length; i++) { if(less(a[i], a[i-1])) return false; } return true; } }