归并排序其实是采用的是分治算法,也就是分而治之,比如一个数组:
{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
明显快了很多。