您的位置:首页 > 编程语言 > Java开发

排序算法_归并排序

2018-02-22 10:33 246 查看
    归并排序算是分而制之策略里的典型算法之一。
    先来看看wikipeda上的gif图:



    它的提出,是为了改进前面冒泡和选择排序存在的问题,对于后两种排序,随着问题规模的翻倍,其运行时间会增长到4倍。如果我们反过来思考,将问题的规模减小一半,那么运行时间就是原来的四分之一。有了这个事实,将数组拆散再按序合并的这种应用递归的分而治之的归并排序就有了理论依据。
    考虑到下列一组序列:



    我们把这个包含8个元素的较小数组分成两个长度为4的数组,然后对这两个较小数组排序,就是下面这个样子:



    让我们把这个数组里的元素挨个合并到一个数组里:
    




很容易把这个调选较小值并插入到新数组过程进行下去,直到重建了整个数组。

分析一下,归并排序的基本框架如下:
1、检查该数组是否为空或只有一个元素。如果是,它必然是有序的。这就有了递归的最简单情况。
2、将数组分解成两个较小的数组,每个数组的大小都是原来数组的一半。
3、递归地对每个较小的数组排序。
4、将两个排序好的数组合并到原来的数组中。

合并部分的代码需要两个“指针”来记录移动当前位置,核心代码为: for (int i = 0; i < array.length; i++) {
if (p2 == n2 || (p1 < n1 && a1[p1] < a2[p2])) {
array[i] = a1[p1++];
} else {
array[i] = a2[p2++];
}
}

完整示例代码为:public class MergeSort {

/**
* Sorts an array of integers into ascending order.
*/

public void sort(int[] array) {
if (array.length > 1) {
int half = array.length / 2;
int[] a1 = subarray(array, 0, half);
int[] a2 = subarray(array, half, array.length);
sort(a1);
sort(a2);
merge(array, a1, a2);
}
}

/**
* Merges the two sorted array a1 and a2 into the array storage passed
* as the first parameter.
*/

private void merge(int[] array, int[] a1, int[] a2) {
int n1 = a1.length;
int n2 = a2.length;
int p1 = 0;
int p2 = 0;
for (int i = 0; i < array.length; i++) {
if (p2 == n2 || (p1 < n1 && a1[p1] < a2[p2])) {
array[i] = a1[p1++];
} else {
array[i] = a2[p2++];
}
}
}

/**
* Creates a new array that contains the elements from array starting
* at p1 and continuing up to but not including p2.
*/

private int[] subarray(int[] array, int p1, int p2) {
int[] result = new int[p2 - p1];
for (int i = p1; i < p2; i++) {
result[i - p1] = array[i];
}
return result;
}

public static void main(String[] args) {
int[] array = new int[]{56, 25, 37, 58, 95, 19, 73, 30};
new MergeSort().sort(array);
System.out.println("After mergeSort, the array is:");
for (int a : array)
System.out.printf("%-5d", a);
System.out.println();
}
}

归并排序更加适合规模较大的序列。
 复杂度分析:
假设长度为N的序列,每一次分解,N都会除以2,假设分成k级,就有
N = 2^k
级别数量k = log2N
而每一级中要完成的工作量又和N成正比,所以工作量与N*log2N成正比。
用不同的底计算得到的对数只差整数倍,故讨论复杂度的时候忽略对数的底。
综上,归并排序的复杂度为:
O(NlogN)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息