Hello World

归并排序

1. 归并排序

1.1 排序原理

  • 采用分治思想,一般用递归实现
  • 将一个无序数组从中间分成两个无序数组,然后对两个无序数组排序,排序之后再将两个有序数组合并为一个有序数组;

1.2 性能分析

1.2.1 执行效率

  它的效率和原始数组的元素顺序无关,效率稳定;最好,最坏,平均复杂度都一样;

  假设n个元素的排序时间为T(n),那么两个子数组的排序时间就是2*T(n/2),合并两个子数组的时间是O(n);

  则T(n)= 2*T(n/2)+ n ;继续分解如下

T(n) = 2*T(n/2) + n
     = 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n
     = 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
     = 8*(2*T(n/16) + n/8) + 3*n = 16*T(n/16) + 4*n
     ......
     = 2^k * T(n/2^k) + k * n
     ......

  T(n/2^k)最小时等于T(1);即 n/2^k = 1 时,k = log2n, 带入上述公式,

  T(n)=Cn+nlog2n,

  用大O表示法表示为T(n)=O( n log n);

1.2.2  空间复杂度

  每次合并数组时需要申请额外空间,但是每次合并完后都会释放内存,最多申请N个元素的空间,所以空间复杂度是O(n),所以不是原地排序算法。

1.2.3 算法稳定性 

  在合并两个较小的数组时,可以元素相等时优先将前面的元素拷贝到临时数组,这样就可以保证稳定性。

1.3 代码实现

// 递归调用函数
      private static void mergeSortInternally(int[] a, int start, int end) {
        // 递归终止条件
        if (start >= end) return;

        // 取start到end之间的中间位置mid,防止(start+end)的和超过int类型最大值
        int mid = start + (end - start)/2;
        // 分治递归
        mergeSortInternally(a, start, mid);
        mergeSortInternally(a, mid+1, end);

        // 将a[start...mid]和A[mid+1...end]合并为A[start...end]
        merge(a, start, mid, end);
      }

      private static void merge(int[] a, int p, int q, int r) {
        int i = p;
        int j = q+1;
        int k = 0; // 初始化变量i, j, k
        int[] tmp = new int[r-p+1]; // 申请一个大小跟a[p...r]一样的临时数组
        while (i<=q && j<=r) {

          if (a[i] <= a[j]) {    
            tmp[k++] = a[i++];  
          } else {
            tmp[k++] = a[j++];    
          }
          
          // 当一个数组中的元素全部拷贝到tmp中时,就将另一个数组剩余的元素也全部拷贝到tmp中
          if (i == (q+1)){
            while(j<=r){
                tmp[k++] = a[j++];
            }
          }
          
          if (j == (r+1)){
            while(i<=q){
                tmp[k++] = a[i++];
            }
          }
          
        }

//        // 判断哪个子数组中有剩余的数据
//        int start = i;
//        int end = q;
//        if (j <= r) {
//          start = j;
//          end = r;
//        }
//
//        // 将剩余的数据拷贝到临时数组tmp
//        while (start <= end) {
//          tmp[k++] = a[start++];
//        }

        // 将tmp中的数组拷贝回a[p...r]
        for (i = 0; i <= r-p; ++i) {
          a[p+i] = tmp[i];
        }
      }

 

posted @ 2019-03-06 22:26  小小忧愁米粒大  阅读(386)  评论(0编辑  收藏  举报
瞅啥瞅,好好看书