归并排序(Merge sort),是建立在归并操作上的一种有效的排序算法,效率为O(n logn),1945年由约翰诺依曼首次提出,该算法是采用分治法的一个非常典型的应用,且各层分治递归可以同时进行。
                        ——Wikipedia


本文将介绍以下内容

排序原理
算法实现(JAVA)
测试阶段
算法分析

采用分治的做法,将一个数组分为两个序列,将序列继续拆分达到最小,分别排序,最后将有序的序列归并,达到全部有序的效果。

  1. public class MergeSort {
  2. private static int[] temp; //临时数组
  3. public static void merge(int[] a, int low, int mid, int high){
  4. int i = low; //第一序列首
  5. int j = mid + 1; //第二序列首
  6. for (int k = low; k <= high ; k++) {
  7. temp[k] = a[k]; //复制元素
  8. }
  9. for (int k = low; k <= high; k++) {
  10. if(i > mid){ //第一序列的全部元素已归并
  11. a[k] = temp[j++];
  12. }
  13. else if(j > high){ //第二序列的全部元素已归并
  14. a[k] = temp[i++];
  15. }
  16. else if(temp[j] < temp[i]){ //第二序列的元素小于第一序列元素
  17. a[k] = temp[j++];
  18. }
  19. else{
  20. a[k] = temp[i++]; //第一序列的元素小于第二序列
  21. }
  22. }
  23. }
  24. }

归并的操作就是依次从序列中选取元素,两个序列中的元素比较,哪个小选哪个,一个序列全部选完了,就直接选择另一个序列的全部元素

  1. public static void sort(int[] a){
  2. temp = new int[a.length];
  3. sort(a, 0, a.length - 1); //排序整个数组
  4. }
  5. private static void sort(int[] a, int low, int high){
  6. if(low >= high){
  7. return;
  8. }
  9. int mid = low + (high - low) / 2;
  10. sort(a, low, mid); //排序左半边
  11. sort(a, mid + 1, high); //排序右半边
  12. merge(a, low, mid, high); //归并
  13. }

sort 方法的作用就是递归执行自己,直到将序列拆分至最小,然后用 merge 方法来排序,最后归并

  1. public class MergeSort {
  2. private static int[] temp; //临时数组
  3. private static void merge(int[] a, int low, int mid, int high){
  4. int i = low; //第一序列首
  5. int j = mid + 1; //第二序列首
  6. for (int k = low; k <= high ; k++) {
  7. temp[k] = a[k]; //复制元素
  8. }
  9. for (int k = low; k <= high; k++) {
  10. if(i > mid){ //第一序列的全部元素已归并
  11. a[k] = temp[j++];
  12. }
  13. else if(j > high){ //第二序列的全部元素已归并
  14. a[k] = temp[i++];
  15. }
  16. else if(temp[j] < temp[i]){ //第二序列的元素小于第一序列元素
  17. a[k] = temp[j++];
  18. }
  19. else{
  20. a[k] = temp[i++]; //第一序列的元素小于第二序列
  21. }
  22. }
  23. }
  24. private static void sort(int[] a){
  25. temp = new int[a.length];
  26. sort(a, 0, a.length - 1); //排序整个数组
  27. }
  28. private static void sort(int[] a, int low, int high){
  29. if(low >= high){
  30. return;
  31. }
  32. int mid = low + (high - low) / 2;
  33. sort(a, low, mid); //排序左半边
  34. sort(a, mid + 1, high); //排序右半边
  35. merge(a, low, mid, high); //归并
  36. }
  37. }
  1. public static void main(String[] args){
  2. int[] a = new int[10];
  3. for (int i = 0; i < 10; i++) {
  4. a[i] = (int)(Math.random() * 100);
  5. System.out.print(a[i] + " ");
  6. }
  7. System.out.println();
  8. sort(a);
  9. for (int i = 0; i < 10; i++) {
  10. System.out.print(a[i] + " ");
  11. }
  12. }

生成十个随机数字,并调用排序方法,接下来选取几组测试结果:

归并排序将所有元素复制到一个辅助数组中,将归并后的结果放入原数组中,不需要额外的空间

这里需要用一些数学公式:

  1. 设数组的长度为N,用 T(N) 表示排序一个长度为N的数组所需要的比较次数,可想而知,T(0) 和 T(1) 为0

  2. 将数组的两边分别排序各需要 N/2 次比较(上限),归并所需次数为N(上限)

  3. 所以 T(N) ≤ T(N/2) + T(N/2) + N

  4. 设 N = 2n且不等式的等号成立:
    T(2n) = 2T(2n-1) + 2n
    (N / 2 = 2n – 1)

  5. 等式两边同时除以2n,得到:
    T(2n) / 2n = T(2n-1) / 2n – 1 + 1

  6. 由上式可以得到:
    T(2n – 1) / 2n – 1 = T(2n-2) / 2n – 2 + 1

  7. 将 6 的结果代入 5 中,得到:
    T(2n) / 2n = T(2n-2) / 2n – 2 + 1 + 1

  8. 重复第7步,直到得到如下结果:
    T(2n) / 2n = T(20)/20 + n
    (共计 n – 1 步)

  9. 等式两边同时乘以 2n ,得到结果:
    T(N) = 2n T(20) + n 2n = NlogN
    ( n = logN)

所以,算法复杂度为O(nlogn)

当两个元素相等时,归并排序不会将两者交换,所以归并排序是稳定的

关于归并排序的介绍就到此了,谢谢!

版权声明:本文为lihanxiang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/lihanxiang/p/8456908.html