归并排序java实现

来源:互联网 发布:知乎4.7怎么不能提问 编辑:程序博客网 时间:2024/05/21 08:39
归并排序是另一类不同的排序方法,所谓归并,就是把两个或者两个以上的有序表合并成一个新的有序表的过程。


归并排序的基本思想:

将一个含有n个序列的有序表看成是n个长度为1的有序表,然后两两归并,得到[n/2]个长度为2的有序表,然后再两两归并,直到得到一个长度为n的有序表为止。

下面是归并排序的一个简单的例子:

初始值 【49】 【38】 【65】 【97】 【76】 【13】 【27】 

看成由长度为1的7个子序列组成 

第一次合并之后 【38 49】 【65 97】 【13 76】 【27】 

看成由长度为1或2的4个子序列组成 

第二次合并之后 【38 49 65 97】 【13 27 76】 

看成由长度为4或3的2个子序列组成 

第三次合并之后 【13 27 38 49 65 76 97】 

递归实现代码:

  1. public class MergeSort {  
  2.     /** 
  3.      * 归并排序 
  4.      * 简介:将两个(或两个以上)有序表合并成一个新的有序表 即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列 
  5.      * 时间复杂度为O(nlogn) 
  6.      * 稳定排序方式 
  7.      * @param nums 待排序数组 
  8.      * @return 输出有序数组 
  9.      */  
  10.     public static int[] sort(int[] nums, int low, int high) {  
  11.         int mid = (low + high) / 2;  
  12.         if (low < high) {  
  13.             // 左边  
  14.             sort(nums, low, mid);  
  15.             // 右边  
  16.             sort(nums, mid + 1, high);  
  17.             // 左右归并  
  18.             merge(nums, low, mid, high);  
  19.         }  
  20.         return nums;  
  21.     }  
  22.   
  23.     public static void merge(int[] nums, int low, int mid, int high) {  
  24.         int[] temp = new int[high - low + 1];  
  25.         int i = low;// 左指针  
  26.         int j = mid + 1;// 右指针  
  27.         int k = 0;  
  28.   
  29.         // 把较小的数先移到新数组中  
  30.         while (i <= mid && j <= high) {  
  31.             if (nums[i] < nums[j]) {  
  32.                 temp[k++] = nums[i++];  
  33.             } else {  
  34.                 temp[k++] = nums[j++];  
  35.             }  
  36.         }  
  37.   
  38.         // 把左边剩余的数移入数组  
  39.         while (i <= mid) {  
  40.             temp[k++] = nums[i++];  
  41.         }  
  42.   
  43.         // 把右边边剩余的数移入数组  
  44.         while (j <= high) {  
  45.             temp[k++] = nums[j++];  
  46.         }  
  47.   
  48.         // 把新数组中的数覆盖nums数组  
  49.         for (int k2 = 0; k2 < temp.length; k2++) {  
  50.             nums[k2 + low] = temp[k2];  
  51.         }  
  52.     }  
  53.   
  54.       
  55.     // 归并排序的实现  
  56.     public static void main(String[] args) {  
  57.   
  58.         int[] nums = { 2783169054 };  
  59.   
  60.         MergeSort.sort(nums, 0, nums.length-1);  
  61.         System.out.println(Arrays.toString(nums));  
  62.     }  
  63. }  
非递归实现代码:

  1. public class MergeDemo{  
  2.     public static void main(String[] args) {  
  3.         String[] a= {"9","8","7","6","5","4","3","2","1"};  
  4.         Object[] aux = (Object[])a.clone();  
  5.         mergeSort(aux, a);  
  6.         for(int i=0;i<a.length;i++){  
  7.             System.out.println(a[i]);  
  8.         }  
  9.     }  
  10.   
  11.     //每个拆分的列表元素个数<=3  
  12.     private static final int INSERTIONSORT_THRESHOLD = 3;  
  13.     /** 
  14.      *  
  15.      * 归并排序(非递归实现) 
  16.      */  
  17.     public static void mergeSort(Object[] src,Object[] dest){  
  18.         int spreCount = INSERTIONSORT_THRESHOLD;       
  19.         int low,mid,high;  
  20.         int len = src.length;  
  21.         if(len <= INSERTIONSORT_THRESHOLD*2){        //如果只能划分为两组,直接排序  
  22.             sort(dest,0,len);  
  23.             return;  
  24.         }  
  25.         while(spreCount < len){  
  26.             for(int i=0;i<len;i=high){   //依次排序归并相邻两个列表  
  27.                 low = i;      
  28.                 high = low + spreCount * 2 ;  
  29.                 mid = low + spreCount;  
  30.                 if(high >= len){  
  31.                     high = len;  
  32.                 }  
  33.                 int l = high - low;  
  34.                 if(l <= INSERTIONSORT_THRESHOLD){  
  35.                     sort(src,low,high);  
  36.                     break;  
  37.                 }  
  38.   
  39.                 if(spreCount == 3){     //所有拆分的列表只进行一次排序  
  40.                     sort(dest,low,mid);  
  41.                     sort(dest,mid,high);  
  42.                 }  
  43.                 if(l == len)    //最后一次归并把src有次序的赋给dest  
  44.                     Merge(src,dest,low,mid,high);  
  45.                 else  
  46.                     Merge(dest,src,low,mid,high);  
  47.   
  48.             }  
  49.             spreCount *= 2;  
  50.         }  
  51.           
  52.     }  
  53.     //对拆分的每个列表进行排序  
  54.     private static void sort(Object[] dest,int low,int high){  
  55.         for (int i = low; i < high; i++){  
  56.             for (int j = i; j > low ; j--){  
  57.                 if(((Comparable) dest[j - 1]).compareTo(dest[j]) > 0){  
  58.                     swap(dest, j-1, j);   
  59.                 }  
  60.             }  
  61.         }  
  62.     }  
  63.       
  64.     //归并相邻两个列表并保存在dest中  
  65.     private static void Merge(Object[] src, Object[] dest, int low, int mid,  
  66.             int high) {  
  67.         int i = low;  
  68.         int p = low;    //第一个列表指针  
  69.         int q = mid;    //第二个列表指针  
  70.         while(p < mid && q <high){  
  71.             if(((Comparable) src[p]).compareTo(src[q]) <= 0){  
  72.                 dest[i++] = src[p++];  
  73.             }else{  
  74.                 dest[i++] = src[q++];  
  75.             }  
  76.         }  
  77.         //添加剩余的值  
  78.         while(p < mid && i<high){  
  79.             dest[i++] = src[p++];  
  80.         }  
  81.         while(q < high && i<high){  
  82.             dest[i++] = src[q++];  
  83.         }  
  84.           
  85.     }  
  86.       
  87.     private static void swap(Object[] x, int a, int b) {  
  88.         Object t = x[a];  
  89.         x[a] = x[b];  
  90.         x[b] = t;  
  91.     }  
  92.    
  93.   
  94. }  

性能分析:

时间复杂度:

由于归并的趟数,等于树的高度Logn,每趟归并需要移动记录n次,因此归并排序的时间复杂度为nlogn.

空间复杂度:

从上面的算法可以看出,需要一个辅助空间num2,其长度等于n,所以归并排序的辅助空间为O(n).

稳定性:

归并排序不涉及到交换,因此它是一种稳定的排序算法。

归并排序是典型的用空间去换取时间,它的时间开销比简单排序要优越,但需要与序列等长的辅助空间。


0 0
原创粉丝点击