算法原理:
归并排序使用分治的思想(divide and conquer):
1. 首先把数组平均分成两个子数组
2. 对两个字数组递归的使用归并排序进行排序
3. 把两个已经排好序的字数组合并得到结果
归并算法的原理图如下:
从图中可以看到归并排序把子问题的规模降低到1的时候停止,一个元素的数组一定是有序的。
算法伪代码:
伪代码来自算法导论归并排序算法部分:
MERGESORT(int[] A, int p, int r)
if(p < r)
then q= (p+r)/2MERGESORT(A, p, q)MERGESORT(A, q+1, r)MERGE(A, p, q, r)
MERGE(int[] A, int p, int q, int r)
n1 = q-p+1
n2 = r-q
create arrays L[1..n1+1] and R[1..n2+1]
for i=1 to n1
L[i] = A[p+i-1]
for j=1 to n2
R[j] = A[q+j]
L[n1+1] = MAX_VALUE //此处在数组的最后放上最大的正整数方便在下面合并的时候控制数组的边界,防止越界
R[n2+1] = MAX_VALUE
i = 1
j = 1
for k=p to r
do if L[i] <= R[j]
then A[k] = L[i]
i = i+1
else A[k] = R[j]
j = j+1
算法性能分析:
时间复杂度:O(nlogn)
归并排序的时间复杂度分析使用分治的时间复杂度分析方法。
每次把数组平均分成两个子数组,问题的规模分解为2T(n/2),在含有n个元素的子数组上,合并所需要的时间是n,因此时间复杂度公式为:
空间复杂度:O(n)T(n) = 2T(n/2) + cn
稳定性:稳定
归并排序的Java版本实现:
private void sort(int[] A, int start, int end)
{
if(start < end)
{
int mid = start + (end - start)/2;
sort(A, start, mid);
sort(A, mid+1, end);
merge(A, start, mid, end);
}
}
private void merge(int[] A, int p, int q, int r)
{
int len1 = q - p +1;
int len2 = r - q;
int[] left = new int[len1+1];
int[] right = new int[len2+1];
left[len1] = Integer.MAX_VALUE;
right[len2] = Integer.MAX_VALUE;
for(int i=0;i<len1;i++)
left[i] = A[p+i];
for(int j=0;j<len2;j++)
right[j] = A[q+j+1];
int i=0;
int j=0;
for(int k=p;k<=r;k++)
{
if(left[i] <= right[j])
{
A[k] = left[i];
i++;
}
else
{
A[k] = right[j];
j++;
}
}
}