只有比別人更早、更勤奮地努力,才能嘗到成功的滋味。 ------麥克馬斯特大學訓言
記得之前總結過插入排序,有興趣的可以看看---插入排序。
如果在最復雜的情況下,所要排序的整個數列是逆序的,當第 i-1 趟需要將 第 i 個元素插入前面的 0~ i -1 個元素的序列當中的時候,它總是會從第 i -1 個元素開始,逐個比較每個元素的大小,直到找到相應的位置。
這個算法中絲毫沒有考慮當要插入第 i 個元素時前面的 0~~ i -1 序列是有序的這個特點。今天要總結的這個算法就充分的利用了這一點。
算法的基本過程:
1)計算 0 ~ i-1 的中間點,用 i 索引處的元素與中間值進行比較,如果 i 索引處的元素大,說明要插入的這個元素應該在中間值和剛加入i索引之間,反之,就是在剛開始的位置 到中間值的位置,這樣很簡單的完成了折半;
2)在相應的半個范圍里面找插入的位置時,不斷的用(1)步驟縮小范圍,不停的折半,范圍依次縮小為 1/2 1/4 1/8 .......快速的確定出第 i 個元素要插在什么地方;
3)確定位置之后,將整個序列后移,並將元素插入到相應位置。
算法實現:
import java.util.*; public class BinaryInsertSort { private static int[] Sort(int[] arr) { int i, j; //保存中間插入的值 int insertNote = 0; //將待排序的數列保存起來 int[] array = arr; System.out.println("開始排序:"); for (i = 1; i < array.length; i++) { int low = 0; int high = i - 1; insertNote = array[i]; //不斷的折半 while (low <= high) { //找出中間值 int mid = (low + high) / 2; //如果大於中間值 if (array[i] > array[mid]) { //在大於中間值的那部分查找 low = mid+1; } else //在小於中間值的那部分查找 high = mid-1; } //將整體數組向后移 for ( j=i; j > low; j--) { array[j] = array[j - 1]; } //插入到指定的位置 array[low] = insertNote; System.out.println(Arrays.toString(array)); } System.out.println("排序之后:"); System.out.println(Arrays.toString(array)); return array; } public static void main(String[] args) { Random random = new Random(); int[] array = new int[10]; for (int i = 0; i < 10; i++) { array[i] = Math.abs(random.nextInt() % 100); } System.out.println("排序之前:"); System.out.println(Arrays.toString(array)); BinaryInsertSort.Sort(array); } }
輸出截圖:
算法分析:
1)時間復雜度:
折半插入排序比直接插入排序明顯減少了關鍵字之間的比較次數,但是移動次數是沒有改變。所以,折半插入排序和插入排序的時間復雜度相同都是O(N^2),在減少了比較次數方面它確實相當優秀,所以該算法仍然比直接插入排序好。
2)空間復雜度:
折半插入排序和插入排序一樣只需要一個多余的緩存數據單元來放第 i 個元素,所以空間復雜度是O(1),因為排序前2個相等的數在序列的前后位置順序和排序后它們兩個的前后位置順序相同,所以它是一個穩定排序。