归并排序其实是采用的是分治算法,也就是分而治之,比如一个数组:
{13,4,5,2,65,6},首先将这个数组分成{13,4,5},{2,65,6} ,然后继续分解{13,4} {5},{2,65},{6},最后{13},{4},{5},{2},{65},{6}
递归分解多个数组后就开始比较合并,首先是13跟4比较,再合并{4,13},然后合并的就是{4,5,13},接着{2,65},{2,6,65} ,最后{2,4,5,6,13,65} , 就是分组合并,时间复杂度是o(nlogn) ,空间复杂度是o(n);也是一种稳定的排序,在代码实现上其实跟快速排序是差不多的,只不过快排是根据一个位置分成左边小于分界点,右边大于分界点。下面看代码:
public static void MergeSort(int []a , int start , int end,int []temp) { if(start < end) { int mid = (start + end ) / 2; MergeSort(a,start,mid,temp); //左边有序 MergeSort(a,mid+1,end,temp); //右边有序 MergerArray(a,start,mid,end,temp); //合并 } } //合并2个数组 public static void MergerArray(int []a,int start , int mid , int end , int []temp) { int i = start , j = end ,m = mid+1; int count = 0; while(i <= mid && m <= j) { if(a[i] < a[m]) { temp[count++] = a[i++]; }else { temp[count++] = a[m++]; } } while(i <= mid) { temp[count++] = a[i++]; } while(m <= j) { temp[count++] = a[m++]; } for(int k = start, s=0 ; k <= end ; k++) { a[k] = temp[s++]; } }
下面测试下排序的速度:
public static void main(String[] args) { Instant start = Instant.now(); int a [] = new int [10000]; for(int i = 0 ; i < 10000 ; i++) { a[i] = 10000 - i; } int temp[] = new int [10000]; MergeSort(a,0,10000-1,temp); for (int i = 0 ; i < 10000 ; i ++) { System.out.println(a[i] + " "); } Instant end = Instant.now(); System.out.println("归并排序所花费的时间 : "+Duration.between(start, end).toMillis()); }
10000个数字进行逆序排列,对比快排:
.... 9993 9994 9995 9996 9997 9998 9999 10000 归并排序所花费的时间 : 147
下面是快速排序:
public static void QuickSorted(int a[], int start , int end) { if(start < end) { int mid = Partition(a,start,end); QuickSorted(a, start , mid-1); QuickSorted(a, mid+1 , end); } } private static int Partition(int[] a, int start, int end) { int i = start , j = end; int temp = a[start]; while(i < j ) { while(i < j && a[j] >= temp) { j--; } a[i] = a[j]; while(i < j && a[i] <= temp) { i++; } a[j] = a[i]; } a[i] = temp; return i; }
public static void main(String[] args) { Instant start = Instant.now(); int a [] = new int [10000]; for(int i = 0 ; i < 10000 ; i++) { a[i] = 10000 - i; } QuickSorted(a,0,10000-1); for (int i = 0 ; i < 10000 ; i ++) { System.out.println(a[i] + " "); } Instant end = Instant.now(); System.out.println("快速排序所花费的时间 : "+Duration.between(start, end).toMillis()); }
.... 9992 9993 9994 9995 9996 9997 9998 9999 10000 快速排序所花费的时间 : 193
快速排序和堆排序都是o(nlogn)的排序,下面在对比下o(n*n)的 排序,下面就以冒泡排序为例:
private static void BubbleSorted(int[] a) { for(int i = 0 ; i < a.length - 1 ; i ++) { for(int j = 0 ; j < a.length - 1 - i ; j++) { if(a[j] > a[j+1]) { int temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; } } } }
public static void main(String []args){ Instant start = Instant.now(); int a [] = new int [100000]; for(int i = 0 ; i < 100000 ; i++) { a[i] = 100000 - i; } BubbleSorted(a); for (int i = 0 ; i < 100000 ; i ++) { System.out.println(a[i] + " "); } Instant end = Instant.now(); System.out.println("冒泡排序所花费的时间 : "+Duration.between(start, end).toMillis()); }
测试10万个数据:
99993 99994 99995 99996 99997 99998 99999 100000 冒泡排序所花费的时间 : 4417
堆排序测试10万个数据:
99992 99993 99994 99995 99996 99997 99998 99999 100000 归并排序所花费的时间 : 953
明显快了很多。