1. 程式人生 > 實用技巧 >歸併排序(自頂向下)

歸併排序(自頂向下)

歸併排序

歸併排序採用的是分治+外排序(不佔用額外記憶體空間),自頂向下

歸併排序大致分為以下幾步驟:

首先要 “分“,假設有【8,4,5,7,1,3,6,2】陣列,分的結果就是通過遞迴每次除2:[8,4,5,7,1,3,6,2]->【[8,4,5,7]和[1,3,6,2]】-->[8,4]、[5,7],[1,3]、[6,2]只不過稍有不同的是,再分的過程中要進行排序再進行合併。

此時8,4進行排序,藉助一個新陣列,按順序填入4,8;隨後再放回原陣列得:[4,8,5,7,1,3,6,2]

再是5,7排後[4,8,5,7,1,3,6,2]

再是4,8,5,7排序後[4,5,7,8,1,3,6,2],此處就體現出了歸併的思想;也是回溯的利用

以此類推排序1,3和6,2和1,3,2,6

最後再總體排一次:[4,5,7,8,1,2,3,6],所有排序都是折半比較,如折半是8,則兩邊都已經是有序的了;接著交替比較兩邊就可得到。

具體程式碼如下:

/*
nums:表示待排序的陣列
left:切分後陣列的起始索引
right:陣列的右邊界
temp:表示外排所需的空間
*/
public static void mergeSort(int[] nums, int left, int right, int[] temp) {
        if (left < right) {
            int mid = (left + right)/ 2;
            mergeSort(nums, left, mid, temp);
//遞迴每次mid左邊所有的元素 mergeSort(nums, mid + 1, right, temp);//每次mid右邊的元素 merge(nums, left, mid, right, temp);//排序 } } public static void merge(int[] nums, int left, int mid, int right, int[] temp) { int l = left; int r = mid + 1; int i = 0; //下面是排序過程
while (l <= mid && r <= right) { if (nums[l] <= nums[r]) { temp[i] = nums[l]; i++; l++; } else { temp[i] = nums[r]; i++; r++; } } //下面是處理剩餘的元素,如3,5,6,7,8;經過上面排序後,那麼就直接將678賦到temp while (l <= mid) { temp[i] = nums[l]; i++; l++; } while (r <= right) { temp[i] = nums[r]; i++; r++; } //下面是將temp陣列排好的元素,轉移到原陣列 int leftTemp = left; i = 0; while (leftTemp <= right) { nums[leftTemp] = temp[i]; i++; leftTemp++; } }

說明:

歸併排序類似一個完全二叉樹,而根據《演算法》第四版給出的證明:歸併排序是一種漸進最優的基於比較排序的演算法;因為歸併排序在最好和最壞情況下時間複雜度都為O(NlgN),所以比較排序的上限和下限都是nlgn。但是具體情況則應另當別論,對於小型陣列,也許選擇或插入排序更快。而這些排序也都是基於比較的排序演算法;也就是說除開比較,還有更優的無需比較的排序演算法,況且歸併排序的空間複雜度O(n)不是最優的。

所有隨筆都是用作簡單複習和參考而已,各位還是要看書或者系統學習,部落格只是個人的一點點認知罷了。