归并排序

归并排序（，或），是建立在归并操作上的一种有效的排序算法，效率为formula_1（大O符号）。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法（Divide and Conquer）的一个非常典型的应用，且各层分治递归可以同时进行。
概述.
采用分治法:
归并操作.
归并操作（merge），也叫归并算法，指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
迭代法（Bottom-up）.
原理如下（假设序列共有formula_2个元素）：
实作范例.
C语言.
迭代版：
int min(int x, int y) {
 return x &lt; y ? x : y;
void merge_sort(int arr[], int len) {
 int *a = arr;
 int *b = (int *) malloc(len * sizeof(int));
 int seg, start;
 for (seg = 1; seg &lt; len; seg += seg) {
 for (start = 0; start &lt; len; start += seg * 2) {
 int low = start, mid = min(start + seg, len), high = min(start + seg * 2, len);
 int k = low;
 int start1 = low, end1 = mid;
 int start2 = mid, end2 = high;
 while (start1 &lt; end1 &amp;&amp; start2 &lt; end2)
 b[k++] = a[start1] &lt; a[start2] ? a[start1++] : a[start2++];
 while (start1 &lt; end1)
 b[k++] = a[start1++];
 while (start2 &lt; end2)
 b[k++] = a[start2++];
 int *temp = a;
 a = b;
 b = temp;
 if (a != arr) {
 int i;
 for (i = 0; i &lt; len; i++)
 b[i] = a[i];
 b = a;
 free(b);
递归版：
// 分治-治
void mergeSort_conquer(int* array, int left, int mid, int right, int* temp) {
 // [left, mid]和[mid+1, right]两个有序数组
 int i = left;
 int j = mid + 1;
 int index = 0;
 while (i &lt;= mid &amp;&amp; j &lt;= right) {
 if (array[i] &lt; array[j]) {
 temp[index++] = array[i++];
 } else {
 temp[index++] = array[j++];
 // 剩余元素直接放入temp
 while (i &lt;= mid) {
 temp[index++] = array[i++];
 while (j &lt;= right) {
 temp[index++] = array[j++];
 // 放回原数组
 index = 0;
 while (left &lt;= right) {
 array[left++] = temp[index++];
// 分治-分
void mergeSort_divide(int* array, int left, int right, int* temp) {
 if (left &lt; right) {
 int mid = left + (right - left) / 2;
 // 左边归并排序
 mergeSort_divide(array, left, mid, temp);
 // 右边归并排序
 mergeSort_divide(array, mid + 1, right, temp);
 // 合并两个有序序列
 mergeSort_conquer(array, left, mid, right, temp);
void mergeSort(int* array, int size) {
 int* temp = (int*)malloc(sizeof(int) * size);
 mergeSort_divide(array, 0, size - 1, temp);
C++.
迭代版：
template&lt;typename T&gt; // 整数或浮点数皆可使用,若要使用物件(class)时必须设定"小于"(&lt;)的运算子功能
void merge_sort(T arr[], int len) {
 T *a = arr;
 T *b = new T[len];
 for (int seg = 1; seg &lt; len; seg += seg) {
 for (int start = 0; start &lt; len; start += seg + seg) {
 int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
 int k = low;
 int start1 = low, end1 = mid;
 int start2 = mid, end2 = high;
 while (start1 &lt; end1 &amp;&amp; start2 &lt; end2)
 b[k++] = a[start1] &lt; a[start2] ? a[start1++] : a[start2++];
 while (start1 &lt; end1)
 b[k++] = a[start1++];
 while (start2 &lt; end2)
 b[k++] = a[start2++];
 T *temp = a;
 a = b;
 b = temp;
 if (a != arr) {
 for (int i = 0; i &lt; len; i++)
 b[i] = a[i];
 b = a;
 delete[] b;
递归版：
void Merge(vector&lt;int&gt; &amp;Array, int front, int mid, int end) {
 // preconditions:
 // Array[front...mid] is sorted
 // Array[mid+1 ... end] is sorted
 // Copy Array[front ... mid] to LeftSubArray
 // Copy Array[mid+1 ... end] to RightSubArray
 vector&lt;int&gt; LeftSubArray(Array.begin() + front, Array.begin() + mid + 1);
 vector&lt;int&gt; RightSubArray(Array.begin() + mid + 1, Array.begin() + end + 1);
 int idxLeft = 0, idxRight = 0;
 LeftSubArray.insert(LeftSubArray.end(), numeric_limits&lt;int&gt;::max());
 RightSubArray.insert(RightSubArray.end(), numeric_limits&lt;int&gt;::max());
 // Pick min of LeftSubArray[idxLeft] and RightSubArray[idxRight], and put into Array[i]
 for (int i = front; i &lt;= end; i++) {
 if (LeftSubArray[idxLeft] &lt; RightSubArray[idxRight]) {
 Array[i] = LeftSubArray[idxLeft];
 idxLeft++;
 } else {
 Array[i] = RightSubArray[idxRight];
 idxRight++;
void MergeSort(vector&lt;int&gt; &amp;Array, int front, int end) {
 if (front &gt;= end)
 return;
 int mid = front + (end - front) / 2;
 MergeSort(Array, front, mid);
 MergeSort(Array, mid + 1, end);
 Merge(Array, front, mid, end);
C#.
public static List&lt;int&gt; sort(List&lt;int&gt; lst) {
 if (lst.Count &lt;= 1)
 return lst;
 int mid = lst.Count / 2;
 List&lt;int&gt; left = new List&lt;int&gt;(); // 定义左侧List
 List&lt;int&gt; right = new List&lt;int&gt;(); // 定义右侧List
 // 以下两个循环把 lst 分为左右两个 List
 for (int i = 0; i &lt; mid; i++)
 left.Add(lst[i]);
 for (int j = mid; j &lt; lst.Count; j++)
 right.Add(lst[j]);
 left = sort(left);
 right = sort(right);
 return merge(left, right);
/// &lt;summary&gt;
/// 合并两个已经排好序的List
/// &lt;/summary&gt;
/// &lt;param name="left"&gt;左侧List&lt;/param&gt;
/// &lt;param name="right"&gt;右侧List&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
static List&lt;int&gt; merge(List&lt;int&gt; left, List&lt;int&gt; right) {
 List&lt;int&gt; temp = new List&lt;int&gt;();
 while (left.Count &gt; 0 &amp;&amp; right.Count &gt; 0) {
 if (left[0] &lt;= right[0]) {
 temp.Add(left[0]);
 left.RemoveAt(0);
 } else {
 temp.Add(right[0]);
 right.RemoveAt(0);
 if (left.Count &gt; 0) {
 for (int i = 0; i &lt; left.Count; i++)
 temp.Add(left[i]);
 if (right.Count &gt; 0) {
 for (int i = 0; i &lt; right.Count; i++)
 temp.Add(right[i]);
 return temp;
Ruby.
def merge list
 return list if list.size &lt; 2
 pivot = list.size / 2
 # Merge
 lambda { |left, right|
 final = []
 until left.empty? or right.empty?
 final « if left.first &lt; right.first; left.shift else right.shift end
 end
 final + left + right
 }.call merge(list[0...pivot]), merge(list[pivot..-1])
end
Java.
递归版：
static void merge_sort_recursive(int[] arr, int[] result, int start, int end) {
 if (start &gt;= end)
 return;
 int len = end - start, mid = (len » 1) + start;
 int start1 = start, end1 = mid;
 int start2 = mid + 1, end2 = end;
 merge_sort_recursive(arr, result, start1, end1);
 merge_sort_recursive(arr, result, start2, end2);
 int k = start;
 while (start1 &lt;= end1 &amp;&amp; start2 &lt;= end2)
 result[k++] = arr[start1] &lt; arr[start2] ? arr[start1++] : arr[start2++];
 while (start1 &lt;= end1)
 result[k++] = arr[start1++];
 while (start2 &lt;= end2)
 result[k++] = arr[start2++];
 for (k = start; k &lt;= end; k++)
 arr[k] = result[k];
public static void merge_sort(int[] arr) {
 int len = arr.length;
 int[] result = new int[len];
 merge_sort_recursive(arr, result, 0, len - 1);
迭代版：
public static void merge_sort(int[] arr) {
 int[] orderedArr = new int[arr.length];
 for (int i = 2; i &lt; arr.length * 2; i *= 2) {
 for (int j = 0; j &lt; (arr.length + i - 1) / i; j++) {
 int left = i * j;
 int mid = left + i / 2 &gt;= arr.length ? (arr.length - 1) : (left + i / 2);
 int right = i * (j + 1) - 1 &gt;= arr.length ? (arr.length - 1) : (i * (j + 1) - 1);
 int start = left, l = left, m = mid;
 while (l &lt; mid &amp;&amp; m &lt;= right) {
 if (arr[l] &lt; arr[m]) {
 orderedArr[start++] = arr[l++];
 } else {
 orderedArr[start++] = arr[m++];
 while (l &lt; mid)
 orderedArr[start++] = arr[l++];
 while (m &lt;= right)
 orderedArr[start++] = arr[m++];
 System.arraycopy(orderedArr, left, arr, left, right - left + 1);
PHP.
function merge_sort($arr) {
 $len = count($arr);
 if ($len &lt;= 1)
 return $arr;
 $half = ($len»1) + ($len &amp; 1);
 $arr2d = array_chunk($arr, $half);
 $left = merge_sort($arr2d[0]);
 $right = merge_sort($arr2d[1]);
 while (count($left) &amp;&amp; count($right))
 if ($left[0] &lt; $right[0])
 $reg[] = array_shift($left);
 else
 $reg[] = array_shift($right);
 return array_merge($reg, $left, $right);
$arr = array(21, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70);
$arr = merge_sort($arr);
for ($i = 0; $i &lt; count($arr); $i++) {
 echo $arr[$i] . ' ';
Python3.
def mergeSort(nums):
 if len(nums) &lt; 2:
 return nums
 mid = len(nums) // 2
 left = mergeSort(nums[:mid])
 right = mergeSort(nums[mid:])
 i = j = 0
 result = []
 while i &lt; len(left) and j &lt; len(right):
 if left[i] &lt; right[j]: 
 result.append(left[i])
 i += 1
 else: 
 result.append(right[j])
 j += 1
 while i &lt; len(left): 
 result.append(left[i]) 
 i += 1
 while j &lt; len(right): 
 result.append(right[j]) 
 j += 1
 return result
if __name__ == "__main__":
 nums = [1, 4, 2, 3.6, -1, 0, 25, -34, 8, 9, 1, 0]
 print("original:", nums)
 print("Sorted:", mergeSort(nums))
Erlang.
%% @doc 归并排序
g_sort([]) -&gt;
g_sort([T]) -&gt;
 [T];
g_sort(L) -&gt;
 g_sort(L, length(L)).
g_sort([_, _ | _] = L, Length) -&gt;
 SplitNum = trunc(Length / 2),
 {L1, L2} = lists:split(SplitNum, L),
 g_merge(g_sort(L1, SplitNum), g_sort(L2, Length - SplitNum));
g_sort(L, _Length) -&gt;
 L.
%% 已经排好序的两个list合并
g_merge([], L2) -&gt;
 L2;
g_merge(L1, []) -&gt;
 L1;
g_merge([T1 | Rest1] = L1, [T2 | Rest2] = L2) -&gt;
 if
 T1 =&lt; T2 -&gt; [T1 | g_merge(Rest1, L2)];
 true -&gt; [T2 | g_merge(L1, Rest2)]
 end.
Javascript.
递归法
function merge(left, right){
 var result = [];
 while(left.length &gt; 0 &amp;&amp; right.length &gt; 0){
 if(left[0] &lt; right[0]){
 result.push(left.shift());
 }else{
 result.push(right.shift());
 return result.concat(left, right);
function mergeSort(arr){
 if(arr.length &lt;=1) return arr;
 var middle = Math.floor(arr.length / 2);
 var left = arr.slice(0, middle);
 var right = arr.slice(middle);
 return merge(mergeSort(left), mergeSort(right));
迭代法
Go.
package main
import (
 "fmt"
 "sort"
func MergeSort(list []int) []int {
 var length = len(list)
 if length &lt; 2 {
 return list
 var mid = length / 2
 return merge(MergeSort(list[:mid]), MergeSort(list[mid:]))
func merge(x, y []int) []int {
 var r []int = make([]int, len(x)+len(y))
 for i, j := 0, 0; ; {
 if i &lt; len(x) &amp;&amp; (j == len(y) || x[i] &lt; y[j]) {
 r[i+j] = x[i]
 i++
 } else if j &lt; len(y) {
 r[i+j] = y[j]
 j++
 } else {
 break
 return r
func main() {
 fmt.Println(MergeSort(list))
 fmt.Println(list)
 sort.Ints(list)
 fmt.Println(list)
递归版
package main
import (
 "fmt"
func merge(data []int) []int {
 sum := len(data)
 if sum &lt;= 1 {
 return data
 left := data[0 : sum/2]
 lSize := len(left)
 if lSize &gt;= 2 {
 left = merge(left)
 right := data[sum/2:]
 rSize := len(right)
 if rSize &gt;= 2 {
 right = merge(right)
 j := 0
 t := 0
 arr := make([]int, sum)
 fmt.Println(left, right, data)
 for i := 0; i &lt; sum; i++ {
 if j &lt; lSize &amp;&amp; t &lt; rSize {
 if left[j] &lt;= right[t] {
 arr[i] = left[j]
 j++
 } else {
 arr[i] = right[t]
 t++
 } else if j &gt;= lSize{
 arr[i] = right[t]
 t++
 } else if t &gt;= rSize{
 arr[i] = left[j]
 j++
 return arr
func main() {
 var bb = merge(aa)
 fmt.Println(bb)
算法复杂度.
比较操作的次数介于formula_5和formula_6。
赋值操作的次数是formula_7。归并算法的空间复杂度为：formula_8