1. 程式人生 > 實用技巧 >十大經典排序演算法(五、歸併排序)

十大經典排序演算法(五、歸併排序)

歸併排序(Merge sort)是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。

作為一種典型的分而治之思想的演算法應用,歸併排序的實現由兩種方法:

  • 自上而下的遞迴(所有遞迴的方法都可以用迭代重寫,所以就有了第 2 種方法);
  • 自下而上的迭代;

和選擇排序一樣,歸併排序的效能不受輸入資料的影響,但表現比選擇排序好的多,因為始終都是 O(nlogn) 的時間複雜度。代價是需要額外的記憶體空間。

演算法步驟

  1. 申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合併後的序列;

  2. 設定兩個指標,最初位置分別為兩個已經排序序列的起始位置;

  3. 比較兩個指標所指向的元素,選擇相對小的元素放入到合併空間,並移動指標到下一位置;

  4. 重複步驟 3 直到某一指標達到序列尾;

  5. 將另一序列剩下的所有元素直接複製到合併序列尾。

JavaScript

 1 function mergeSort(arr) {  // 採用自上而下的遞迴方法
 2     var len = arr.length;
 3     if(len < 2) {
 4         return arr;
 5     }
 6     var middle = Math.floor(len / 2),
 7         left = arr.slice(0, middle),
8 right = arr.slice(middle); 9 return merge(mergeSort(left), mergeSort(right)); 10 } 11 12 function merge(left, right) 13 { 14 var result = []; 15 16 while (left.length && right.length) { 17 if (left[0] <= right[0]) { 18 result.push(left.shift());
19 } else { 20 result.push(right.shift()); 21 } 22 } 23 24 while (left.length) 25 result.push(left.shift()); 26 27 while (right.length) 28 result.push(right.shift()); 29 30 return result; 31 }

Python

 1 def mergeSort(arr):
 2     import math
 3     if(len(arr)<2):
 4         return arr
 5     middle = math.floor(len(arr)/2)
 6     left, right = arr[0:middle], arr[middle:]
 7     return merge(mergeSort(left), mergeSort(right))
 8 
 9 def merge(left,right):
10     result = []
11     while left and right:
12         if left[0] <= right[0]:
13             result.append(left.pop(0))
14         else:
15             result.append(right.pop(0));
16     while left:
17         result.append(left.pop(0))
18     while right:
19         result.append(right.pop(0));
20     return result

C語言

 1 void merge_sort_recursive(int arr[], int reg[], int start, int end) {
 2     if (start >= end)
 3         return;
 4     int len = end - start, mid = (len >> 1) + start;
 5     int start1 = start, end1 = mid;
 6     int start2 = mid + 1, end2 = end;
 7     merge_sort_recursive(arr, reg, start1, end1);
 8     merge_sort_recursive(arr, reg, start2, end2);
 9     int k = start;
10     while (start1 <= end1 && start2 <= end2)
11         reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
12     while (start1 <= end1)
13         reg[k++] = arr[start1++];
14     while (start2 <= end2)
15         reg[k++] = arr[start2++];
16     for (k = start; k <= end; k++)
17         arr[k] = reg[k];
18 }
19 
20 void merge_sort(int arr[], const int len) {
21     int reg[len];
22     merge_sort_recursive(arr, reg, 0, len - 1);
23 }

C++

 1 void Merge(vector<int> &Array, int front, int mid, int end) {
 2     vector<int> LeftSubArray(Array.begin() + front, Array.begin() + mid + 1);
 3     vector<int> RightSubArray(Array.begin() + mid + 1, Array.begin() + end + 1);
 4     int idxLeft = 0, idxRight = 0;
 5     LeftSubArray.insert(LeftSubArray.end(), numeric_limits<int>::max());
 6     RightSubArray.insert(RightSubArray.end(), numeric_limits<int>::max());
 7     // Pick min of LeftSubArray[idxLeft] and RightSubArray[idxRight], and put into Array[i]
 8     for (int i = front; i <= end; i++) {
 9         if (LeftSubArray[idxLeft] < RightSubArray[idxRight]) {
10             Array[i] = LeftSubArray[idxLeft];
11             idxLeft++;
12         } else {
13             Array[i] = RightSubArray[idxRight];
14             idxRight++;
15         }
16     }
17 }
18 
19 void MergeSort(vector<int> &Array, int front, int end) {
20     if (front >= end)
21         return;
22     int mid = (front + end) / 2;
23     MergeSort(Array, front, mid);
24     MergeSort(Array, mid + 1, end);
25     Merge(Array, front, mid, end);
26 }