归并排序详解,与其他排序算法的比较
归并排序
将两个有序的数组归并成一个更大的有序数组
一种简单的方法是:将两个数组归并到第三个数组中(需要额外的空间)
更常见的做法是:避免了开辟额外空间,采用原地归并的方式
原地归并的抽象方法
public static void merge(Comparable[] a, int lo, int mid, int hi){ // 将大数组a分成两个小数组,a[lo, mid], a[mid, hi] 分别进行排序 int j = mid+1; int i = lo; // 数组复制,复制到辅助数组中 System.arraycopy(a, lo, aux, lo, hi); for(int k = lo; k <= hi; k++) { if (i > mid) // 当左侧小数组为空时 a[k] = aux[j++]; else if (j > hi) // 当右侧小数组为空时 a[k] = aux[i++]; // 比较左右两个数组首位,如果aux[j]小于aux[i] else if (less(aux[j], aux[i])) // 将 aux[j] 放入原数组 并索引下移 a[k] = aux[j++]; else // 否则将 aux[i] 放入原数组 并索引下移 a[k] = aux[i++]; } }
自顶向下的归并排序
算法讲究先从上直接递归到最小数组,将最小数组排序
步骤:
- 通过递归将数组不断二分,直到小数组只含有两个元素为止
- 将只含有两个元素的数组排序后,再重新组成上层数组
- 如此反复,直到大数组为止
package Sort; import java.util.Arrays; import java.util.Random; import static Sort.SortExample.isSorted; import static Sort.SortExample.less; public class MergeSort { public static Comparable[] aux; // 主函数,供外界调用 public static void sort(Comparable[] b){ Comparable[] a = new Comparable[b.length]; System.arraycopy(b, 0, a, 0, b.length); // System.out.println(Arrays.toString(b)); aux = new Comparable[a.length]; // 1000 sort(a, 0, a.length-1); // 1000 } // 通过递归将大数组不断划分,直到每个小数组只有两个元素 public static void sort(Comparable[] a, int lo, int hi){ // 将数组a[lo..hi] 排序 if(hi <= lo) return; int mid = lo + (hi-lo)/2; // 4 sort(a, lo, mid); // 左半边排序 sort(a, mid+1, hi); // 右半边排序 merge(a, lo, mid, hi); // 归并结果 } }
自底向上的归并排序
从最小数组开始排序,再排序较大数组,循环渐进地进行
public class MergeSortBU { public static void sort(Comparable[] b){ Comparable[] a = new Comparable[b.length]; System.arraycopy(b, 0, a, 0, b.length); // 进行 lgN 次两两归并 int N = a.length; Comparable[] aux = new Comparable[N]; for(int sz = 1; sz < N; sz *= 2){ // 以2个元素为一个最小数组 for(int lo = 0; lo < N-sz; lo += sz+sz) // 以相邻的两个小数组为一组进行归并 merge(a, lo, lo+sz-1, Math.min(lo+sz+sz-1, N-1)); // 将相邻的两个小数组归并 if(!isSorted(a)) System.out.println("自底向上归并排序失败"); } } }
特点:
- 可以用来实现对链表的排序,只需要重新组织链表连接就能将链表原地排序
注意点:
- 归并排序的空间复杂度不是最优的
- 在实践中不一定会遇到最坏情况
- 除了比较,算法的其他操作(例如:访问数组)也很重要
- 不进行比较也能将某些数据排序
四种排序算法的比较
数据来源:algo4 官方提供的 algo4-data.zip 数据包
先进行1k数据量的比较:
选择排序,1000个数据,执行时间为:0.01177 s 插入排序,1000个数据,执行时间为:0.0137114 s 希尔排序,1000个数据,执行时间为:0.0014275 s 自顶向下归并排序,1000个数据,执行时间为:0.001443 s 自底向上归并排序,1000个数据,执行时间为:3.711E-4 s
进行32k数据量的比较:
选择排序,32000个数据,执行时间为:4.2373938 s 插入排序,32000个数据,执行时间为:2.6435673 s 希尔排序,32000个数据,执行时间为:0.0226827 s 自顶向下归并排序,32000个数据,执行时间为:0.0186592 s 自底向上归并排序,32000个数据,执行时间为:0.0120077 s
其他有关排序算法的文章:
选择排序,插入排序,希尔排序的详解与比较
本文作者:清澈的澈
本文链接:https://www.cnblogs.com/lmc7/p/17531393.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步