归并排序(merge sort)是一个时间复杂度为O(nlogn)的基于比较的排序算法(comparison based sorting algorithm)。 归并排序大多数实现(implementation)都将其实现成了一个stable sort, 所谓的stable sort的意思就是the implementation preserves the input order of equal elements in the sorted order。
merge sort 也采用了divide and conquer(分治技术) 的排序算法。 由John von Neumann于1945年发明的。
我们知道, 快排序的平均情况下时间复杂度是O(nlogn), 最坏情况下为O(n^2)。 归并排序的好处就是时间复杂度总是O(nlogn).。 所以归并排序在时间方面可以beats quick sort。
下面对merge sort做出详细说明:
例如, 我们想要对如下数组精心排序:
merge sort 的思想是将一个problem break into 2 subproblems。
(1)divide the array into 2 equal halves(假如分隔位置在数组的中间(记为mid位置), mid 之前为the first subarray, 之后为the second subarray):
(2) 现在假如我们somehow 将这两个子数组排好序了, 接下来我们的任务就是将这两个子数组merge称为一个大的排好序的数组。 注意这三个数组时独立位于内存之中的(可见merge sort 的空间复杂度会比较大)。
我们的merge算法如下。 现在我们将上图左边的数组记为L, 右边的数组记为R。 首先第一步,比较L的第一个未选中的数据和R中第一个未选中的数据, 找出最小的数据, 为位于L中的1. 我们将这个值放在A中。 然后移动L的索引到下一个元素2, R的索引记录不懂, 比较, 发现2大, 将2 放到A的第二个位置。 在移动L中的索引, 到达4, R的不动, 4 比3大, 所以将3 放在A的第三个位置, 移动R的索引记录到下一个元素。 以此类推, 直至R(或者L)的元素均位于A中, 然后将L(或者R)剩余的元素均拷贝到A中。 即完成排序。
上述算法的伪代码如下:
现在我们说说如何排序。
解决办法是我们可以进一步的将数组或者list 进行进一步的细分:
到达最后一步的时候, 然后开始从下网上归并(merge)。
最终结果如下:
归并排序的伪代码如下:
程序如下:
/* Merge sort in C++ */
#include <cstdio>
#include <iostream>
using namespace std;
// Function to Merge Arrays L and R into A.
// lefCount = number of elements in L
// rightCount = number of elements in R.
void Merge(int *A,int *L,int leftCount,int *R,int rightCount) {
int i,j,k;
// i - to mark the index of left aubarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
i = 0; j = 0; k =0;
while(i<leftCount && j< rightCount) {
if(L[i] < R[j]) A[k++] = L[i++];
else A[k++] = R[j++];
}
while(i < leftCount) A[k++] = L[i++];
while(j < rightCount) A[k++] = R[j++];
}
// Recursive function to sort an array of integers.
void MergeSort(int *A,int n) {
int mid,i, *L, *R;
if(n < 2) return; // base condition. If the array has less than two element, do nothing.
mid = n/2; // find the mid index.
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-array
// and (n-mid) elements (from mid to n-1) will be part of right sub-array
L = new int[mid];
R = new int [n - mid];
for(i = 0;i<mid;i++) L[i] = A[i]; // creating left subarray
for(i = mid;i<n;i++) R[i-mid] = A[i]; // creating right subarray
MergeSort(L,mid); // sorting the left subarray
MergeSort(R,n-mid); // sorting the right subarray
Merge(A,L,mid,R,n-mid); // Merging L and R into A as sorted list.
// the delete operations is very important
delete [] R;
delete [] L;
}
int main() {
/* Code to test the MergeSort function. */
int A[] = {6,2,3,1,9,10,15,13,12,17}; // creating an array of integers.
int i,numberOfElements;
// finding number of elements in array as size of complete array in bytes divided by size of integer in bytes.
// This won't work if array is passed to the function because array
// is always passed by reference through a pointer. So sizeOf function will give size of pointer and not the array.
// Watch this video to understand this concept - http://www.youtube.com/watch?v=CpjVucvAc3g
numberOfElements = sizeof(A)/sizeof(A[0]);
// Calling merge sort to sort the array.
MergeSort(A,numberOfElements);
//printing all elements in the array once its sorted.
for(i = 0;i < numberOfElements;i++)
cout << " " << A[i];
return 0;
}
运行结果为:
NOTE: 在code::blocks 下可以调试, 单步运行, 打开watches 窗口查看各个变量
也可以查看call stack: