歸併排序簡稱Merge sort是一種遞歸思想的排序算法。這個算法的思路就是將要排序的數組分紅不少小的部分,直到這些小的部分都是已排序的數組爲止(只有一個元素的數組)。java
而後將這些排序過的數組兩兩合併起來,組成一個更大一點的數組。接着將這些大一點的合併過的數組再繼續合併,直到排序完整個數組爲止。git
假如咱們有一個數組:29,10,14,37,20,25,44,15,怎麼對它進行歸併排序呢?github
先看一個動畫:算法
咱們來詳細分析一下上面例子的運行過程:數組
首先將數組分爲兩部分,[29,10,14,37]和[20,25,44,15]。ide
[29,10,14,37]又分紅兩部分[29,10]和[14,37]。動畫
[29,10]又被分紅兩部分[29]和[10],而後對[29]和[10]進行歸併排序生成[10,29]。spa
一樣的對[14,37]進行歸併排序獲得[14,37]。3d
將[10,29]和[14,37]再次進行歸併排序獲得[10,14,29,37],以此類推,獲得最後的結果。code
歸併排序主要使用了分而治之的思想。將一個大的數組分紅不少不少個已經排序好的小數組,而後再對小數組進行合併。
這個Divide的過程可使用遞歸算法,由於無論是大數組仍是小數組他們的divide邏輯是同樣的。
而咱們真正作排序的邏輯部分是在合併這一塊。
先看一下最核心的merge部分:
/** *合併兩部分已排序好的數組 * @param array 待合併的數組 * @param low 數組第一部分的起點 * @param mid 數組第一部分的終點,也是第二部分的起點-1 * @param high 數組第二部分的終點 */
private void merge(int[] array, int low, int mid, int high) {
// 要排序的數組長度
int length = high-low+1;
// 咱們須要一個額外的數組存儲排序事後的結果
int[] temp= new int[length];
//分紅左右兩個數組
int left = low, right = mid+1, tempIdx = 0;
//合併數組
while (left <= mid && right <= high) {
temp[tempIdx++] = (array[left] <= array[right]) ? array[left++] : array[right++];
}
//一個數組合並完了,剩下的一個繼續合併
while (left <= mid) temp[tempIdx++] = array[left++];
while (right <= high) temp[tempIdx++] = array[right++];
//將排序事後的數組拷貝回原數組
for (int k = 0; k < length; k++) array[low+k] = temp[k];
}
複製代碼
你們須要注意的是,咱們的元素是存在原始數組裏面的,方法的第一個參數就是原始數組。
後面的三個參數是數組中須要歸併排序的index。三個index將數組劃分紅了兩部分:array[low to mid], array[mid+1 to high]。
merge的邏輯就是對這兩個數組進行合併。
由於咱們的數組自己是存放有原始的,因此要想進行歸併排序,咱們須要藉助一個額外的數組空間int[] temp。
經過比較array[low to mid], array[mid+1 to high]中的元素大小,一個個將元素插入到int[] temp中,最後將排序事後的數組拷貝回原數組,merge完成。
而後咱們再看一下divide的部分,divide部分實際上就是遞歸調用,在遞歸的最後,咱們須要調用merge方法便可:
public void doMergeSort(int[] array, int low, int high){
// 要排序的數組 array[low..high]
//使用二分法進行遞歸,當low的值大於或者等於high的值的時候,就中止遞歸
if (low < high) {
//獲取中間值的index
int mid = (low+high) / 2;
//遞歸前面一半
doMergeSort(array, low , mid );
//遞歸後面一半
doMergeSort(array, mid+1, high);
//遞歸完畢,將排序事後的數組的兩部分合並
merge(array, low, mid, high);
log.info("merge以後的數組:{}",array);
}
}
複製代碼
array是原數組,low和high標記出了要遞歸排序的數組起始位置。
運行下上面的結果:
能夠看到輸出結果和咱們動畫展現的結果是一致的。
咱們看下歸併排序的時間複雜度是怎麼樣的。
首先看merge方法,merge方法實際是遍歷了兩個數組,因此merge方法的時間複雜度是O(N)。
再看一下divide方法:
divide方法將排序分紅了logN層,每層均可以看作是對N個元素的合併排序,所以每層的時間複雜度是O(N)。
加起來,總的時間複雜度就是O(N logN)。
本文的代碼地址:
本文已收錄於 www.flydean.com/algorithm-m…
最通俗的解讀,最深入的乾貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!
歡迎關注個人公衆號:「程序那些事」,懂技術,更懂你!