這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
常見的內部排序演算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸併排序、快速排序、堆排序、基數排序等。用一張圖概括:
歸併排序(英語:Merge sort,或mergesort),是建立在歸併操作上的一種有效排序演算法,效率為O(n log n)。1945年由約翰·馮·諾伊曼首次提出。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用,且各層分治遞迴可以同時進行。
作為一種典型的分而治之思想的演算法應用,歸併排序的實現由兩種方法:
自上而下的遞迴(所有遞迴的方法都可以用迭代重寫,所以就有了第 2 種方法);
自下而上的迭代;
在《資料結構與演算法 JavaScript 描述》中,作者給出了自下而上的迭代方法。但是對於遞迴法,作者卻認為:
However, it is not possible to do so in JavaScript, as the recursion goes too deep for the language to handle.
然而,在 JavaScript 中這種方式不太可行,因為這個演算法的遞迴深度對它來講太深了。
說實話,我不太理解這句話。意思是 JavaScript 編譯器記憶體太小,遞迴太深容易造成記憶體溢出嗎?還望有大神能夠指教。
和選擇排序一樣,歸併排序的效能不受輸入資料的影響,但表現比選擇排序好的多,因為始終都是 O(nlogn) 的時間複雜度。代價是需要額外的記憶體空間。
-
演算法步驟
-
申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合并後的序列;
-
設定兩個指標,最初位置分別為兩個已經排序序列的起始位置;
-
比較兩個指標所指向的元素,選擇相對小的元素放入到合并空間,並移動指標到下一位置;
-
重複步驟 3 直到某一指標達到序列尾;
-
將另一序列剩下的所有元素直接複製到定序序列尾。
-
動圖示範
1、JavaScript 代碼實現
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function mergeSort(arr) { var len = arr.length; if(len < 2) { return arr; } var middle = Math.floor(len / 2), left = arr.slice(0, middle), right = arr.slice(middle); return merge(mergeSort(left), mergeSort(right)); } function merge(left, right){ var result = []; while (left.length && right.length) { if (left[0] <= right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } while (left.length) result.push(left.shift()); while (right.length) result.push(right.shift()); return result; } |
2、Python 代碼實現
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
def mergeSort(arr): import math if(len(arr)<2): return arr middle = math.floor(len(arr)/2) left, right = arr[0:middle], arr[middle:] return merge(mergeSort(left), mergeSort(right)) def merge(left,right): result = [] while left and right: if left[0] <= right[0]: result.append(left.pop(0)); else: result.append(right.pop(0)); while left: result.append(left.pop(0)); while right: result.append(right.pop(0)); return result |
3、Go 代碼實現
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
func mergeSort(arr []int) []int { length := len(arr) if length < 2 { return arr } middle := length / 2 left := arr[0:middle] right := arr[middle:] return merge(mergeSort(left), mergeSort(right)) } func merge(left []int, right []int) []int { var result []int for len(left) != 0 && len(right) != 0 { if left[0] <= right[0] { result = append(result, left[0]) left = left[1:] } else { result = append(result, right[0]) right = right[1:] } } for len(left) != 0 { result = append(result, left[0]) left = left[1:] } for len(right) != 0 { result = append(result, right[0]) right = right[1:] } return result } |
4、Java 實現
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public static int[] sort(int[] nums, int low, int high) { int mid = (low + high) / 2; if (low < high) { sort(nums, low, mid); sort(nums, mid + 1, high); merge(nums, low, mid, high); } return nums; } /** * 將數組中low到high位置的數進行排序 * nums 待排序數組 * low 待排的開始位置 * mid 待排中間位置 * high 待排結束位置 */ public static void merge(int[] nums, int low, int mid, int high) { int[] temp = new int[high - low + 1]; int i = low; int j = mid + 1; int k = 0; while (i <= mid && j <= high) { if (nums[i] < nums[j]) { temp[k++] = nums[i++]; } else { temp[k++] = nums[j++]; } } while (i <= mid) { temp[k++] = nums[i++]; } while (j <= high) { temp[k++] = nums[j++]; } for (int k2 = 0; k2 < temp.length; k2++) { nums[k2 + low] = temp[k2]; } } |
登入樂搏學院官網http://www.learnbo.com/
或關注我們的官方微博,還有更多驚喜哦~