算法——排序之归并排序
来源:互联网 发布:仓库软件多少钱 编辑:程序博客网 时间:2024/06/05 02:14
归并排序
首先将数组分成两个(或两个以上)部分,分别进行排序,然后将这些有序的子数组归并起来。
该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子数组合并,得到完全有序的数组;即先使每个子数组有序,再使子数组间有序。
归并排序最吸引人的是它能够保证任意长度为N的数组排序的时间和NlogN成正比。缺点是他需要的额外的空间也和N成正比。
树状图更加容易理解:
设n为树的层数。第k层的节点是一个大小为2^n-k的数组,在归并的时候,我们需要比较左右两个部分的数组,所以需要比较2^n-k次。又因为第k层有2^k个节点。所以总共需要比较2^n次。
而树的高度为lgN,也就是n,所以最终需要比较NlogN次。
代码如下:
public static void sort(Comparable[] a) { arrayTemp = new Comparable[a.length]; sort1(a, 0, a.length - 1);}private static void sort(Comparable[] a, int begin, int end) { if (begin >= end) return; int mid = (begin + end) / 2; sort(a, begin, mid); //先排序左边 sort(a, mid + 1, end); // 排序右边 merge(a, begin, mid, end); // 归并}private static void merge(Comparable[] a, int low, int mid, int high) { int j = low; int k = mid + 1; for (int i = low; i <= high; i++) { arrayTemp[i] = a[i]; } for (int i = low; i <= high; i++) { if (j >= mid + 1) { // 如果左边没了 a[i] = arrayTemp[k++]; } else if (k >= high + 1) { // 右边没了 a[i] = arrayTemp[j++]; } else if (less(arrayTemp[j], arrayTemp[k])) { // 左边的比较小 a[i] = arrayTemp[j++]; } else { // 右边的比较小 a[i] = arrayTemp[k++]; } }}
改进1:对小规模子数组使用插入排序。当排序的时候,如果发现数组的规模已经比较小了,我们可以使用别的排序方法进行排序。对于小规模的数组,插入排序或者选择排序可能会比归并排序更加快。
改进2:再进行归并操作之前,我们可以比较左边子数组的最后一位a[mid]和右边子数组的第一位a[mid+1],如果发现a[mid]<a[mid+1]。那么数组已经是有序的了。不需要再进行归并。
改进代码:
public static void sort(Comparable[] a) { arrayTemp = new Comparable[a.length]; sort1(a, 0, a.length - 1);}private static void sort(Comparable[] a, int begin, int end) { // 改进1,数组规模小的时候,使用插入排序 if (end - begin <= 7) { InsertSort.sort(a, begin, end + 1); return; } int mid = (begin + end) / 2; sort(a, begin, mid); sort(a, mid + 1, end); // 改进2 if (less(a[mid], a[mid+1])) return; merge(a, begin, mid, end); }private static void merge(Comparable[] a, int low, int mid, int high) { int j = low; int k = mid + 1; for (int i = low; i <= high; i++) { arrayTemp[i] = a[i]; } for (int i = low; i <= high; i++) { if (j >= mid + 1) { // 如果左边没了 a[i] = arrayTemp[k++]; } else if (k >= high + 1) { // 右边没了 a[i] = arrayTemp[j++]; } else if (less(arrayTemp[j], arrayTemp[k])) { // 左边的比较小 a[i] = arrayTemp[j++]; } else { // 右边的比较小 a[i] = arrayTemp[k++]; } }}
我们来比较一下运行结果,顺便比较一下和希尔排序的速度:
public static void main(String[] args) { final int NUM = 1000000; Integer[] a1 = new Integer[NUM]; Integer[] a2 = new Integer[NUM]; Integer[] a3 = new Integer[NUM]; Integer[] a4 = new Integer[NUM]; for (int i = 0; i < NUM; i++) { a1[i] = (int) (Math.random() * NUM); a2[i] = a1[i]; a3[i] = a1[i]; a4[i] = a1[i]; } long startTime; long endTime; startTime = System.currentTimeMillis(); // 获取开始时间 ShellSort.sort(a2); assert isSorted(a2); endTime = System.currentTimeMillis(); System.out.println("shell排序cost: " + (endTime - startTime) + " ms"); startTime = System.currentTimeMillis(); // 获取开始时间 MergeSort.sort1(a3); assert isSorted(a3); endTime = System.currentTimeMillis(); System.out.println("Merge排序cost: " + (endTime - startTime) + " ms"); startTime = System.currentTimeMillis(); // 获取开始时间 MergeSort.sort2(a4); assert isSorted(a4); endTime = System.currentTimeMillis(); System.out.println("Merge排序改良cost: " + (endTime - startTime) + " ms");}运行结果:
shell排序cost: 1281 msMerge排序cost: 423 msMerge排序改良cost: 397 ms普遍来说,改良的Merge排序比之前的Merge排序来说要快。
而归并排序相比较于希尔排序,又有了一个很大的提升。数据量比较大的时候,提升就越明显了。
阅读全文
0 0
- 算法——排序之归并排序
- 算法——排序之归并排序
- 排序算法—归并排序
- 排序算法—归并排序
- 算法之旅——归并排序
- 【算法之家】——归并排序
- 经典排序算法之——归并排序
- 排序算法总结之——归并排序
- 排序算法之五——归并排序
- 排序算法之 —— 归并排序(六)
- 排序算法之归并排序
- 排序算法之归并排序
- 排序算法之归并排序
- 排序算法之归并排序
- 排序算法之归并排序
- 排序算法之归并排序
- 排序算法之归并排序
- 排序算法之归并排序
- 《设计模式之禅》读书笔记-策略模式、享元模式、工厂模式、门面模式混用
- 深入理解JavaScript系列(29):设计模式之装饰者模式
- phpmyadmin的config-default-php文件中各个配置参数的详细说明
- A strange lift HDU
- 图像处理与计算机视觉中的经典文章
- 算法——排序之归并排序
- 关于AppCompatTextView
- 【Redis缓存机制】2.Redis安装和简单使用
- 深入理解JavaScript系列(30):设计模式之外观模式
- android.os.Debug.waitForDebugger()使用需小心
- mysql索引
- hadoop 入门
- C++----声明、定义、const限定符
- bzoj1260