與不少有用的算法相似,合併排序基於這樣一個技巧:將 2 個大小爲 N/2 的已排序序列合併爲一個 N 元素已排序序列僅須要 N 次操做。這個方法叫作合併。html
咱們用個簡單的例子來看看這是什麼意思:java
經過此圖你能夠看到,在 2 個 4元素序列裏你只須要迭代一次,就能構建最終的8元素已排序序列,由於兩個4元素序列已經排好序了:算法
這個方法之因此有效,是由於兩個4元素序列都已經排好序,你不須要再『回到』序列中查找比較。數據庫
在拆分階段過程當中,使用3個步驟將序列分爲一元序列。步驟數量的值是 log(N) (由於 N=8, log(N)=3)。【譯者注:底數爲2,下文有說明】apache
我怎麼知道這個的?api
我是天才!一句話:數學。道理是每一步都把原序列的長度除以2,步驟數就是你能把原序列長度除以2的次數。這正好是對數的定義(在底數爲2時)。數組
在排序階段,你從一元序列開始。在每個步驟中,你應用屢次合併操做,成本一共是 N=8 次運算。服務器
由於有 log(N) 個步驟,總體成本是 N*log(N) 次運算。多線程
爲何這個算法如此強大?框架
由於:
注:這種算法叫『原地算法』(in-place algorithm)
注:這種算法叫『外部排序』(external sorting)。
好比,分佈式合併排序是Hadoop(那個著名的大數據框架)的關鍵組件之一。
這個排序算法在大多數(若是不是所有的話)數據庫中使用,可是它並非惟一算法。若是你想多瞭解一些,你能夠看看 這篇論文,探討的是數據庫中經常使用排序算法的優點和劣勢。
我實現的歸併算法的java 代碼:
/** * 歸併算法 * @param list * @param first * @param last */ public static void mergeSort(int[] list, int first, int last){ if(null == list || list.length < 0 || first == last){ return; } //這個幾行代碼能夠省略 若是省略 那麼當只有2個元素的時候還須要調用此方法遞歸 //那麼其實只有一個元素看成mergeSort入參 其實沒什麼意義 //加上這幾行僅僅是減小几回函數調用 對結果無影響 強迫症者 可刪除。 if(last - first == 1){ sort(list, first, (last + first)/2, last); return; } mergeSort(list, first, (last + first)/2); mergeSort(list, (last + first)/2 + 1, last); sort(list, first, (last + first)/2, last); } //這個方法是合併兩個有序數組 temp數組能夠不須要,直接對list 相應位置的元素操做便可 //那麼這麼作合併元素就好像直接插入排序算法同樣,前半部分數組不動,後半部分數組比較插入 public static void sort(int[] list, int first, int mid, int last ){ int[] temp = new int[last - first + 1]; int i = 0; int j = 0; int index = 0; while(i < mid - first + 1 && j < last - mid){ if(list[first + i] >= list[mid + 1 + j]){ temp[index] = list[mid + 1 + j]; j++; index++; } else { temp[index] = list[first + i]; i++; index++; } } while(i < mid - first + 1){ temp[index] = list[first + i]; index++; i++; } while(j < last - mid){ temp[index] = list[mid + 1 + j]; index++; j++; } for(int k = first, n = 0; k <= last; k++, n++){ list[k] = temp[n]; } System.out.println(Arrays.toString(list)); }