这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
归并排序
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用
归并操作
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序 若将两个有序表合并成一个有序表,称为二路归并
算法基本思想
- 将n个元素从中间切开,分成左右两部分,此处不要求左右两部分个数完全相等,由于奇偶的影响左边可能比右边多1个数
- 将步骤1分成的左右两部分再分别进行递归分解。直到将所有的元素分离成长度为1的单个元素。
- 对单个元素进行逐一排序
- 从最底层开始逐步合并两个排好序的数列。
复杂度解析
归并排序时间复杂度为O(N*logN),额外的空间复杂度O(N)
使用场景解析
归并排序适用于数据量大,并且对稳定性有要求的情况。但前面介绍的从单个记录起进行两两归并的排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子序列,然后再将其两两归并。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的
代码实现
java
import java.util.Arrays;
public class MergeSort1 {
public static void main(String[] args) {
//先生成一个随机数组发生器
int testTime = 500000;
int maxSize =100;
int maxValue=100;
boolean succeed = true;
for (int i = 0 ; i <testTime;i++){
int[] arr1 = generateRandomArray(maxSize,maxValue);
int[] arr2 = copyArray(arr1);
mergeSort(arr1);
comparator(arr2); //将数组arr2用自带的默认排序器进行排序
if(!isEqual(arr1,arr2)){
succeed=false;
printArray(arr1);
printArray(arr2);
break;
}
}
System.out.println(succeed?"Nice":"fucking fucked");
int[] arr = generateRandomArray(maxSize,maxValue);
printArray(arr);
mergeSort(arr);
printArray(arr);
}
//test
public static int[] generateRandomArray(int maxSize,int maxValue){
int[] arr = new int[(int)((maxSize+1)*Math.random())]; //生成一个0到100维之间随机大小的数组
for(int i =0 ; i<arr.length;i++){
arr[i]=(int)((maxValue+1)*(Math.random()))-(int)((maxValue)*Math.random()); //生成两个0-100之间随机大小的整数,然后将两个整数相减
}
return arr;
}
//test
public static int[] copyArray(int[] arr){
if(arr==null){
return null;
}
int[] res = new int[arr.length];
for(int i = 0 ;i <arr.length;i++){
res[i]=arr[i];
}
return res;
}
//test
public static void comparator(int[] arr){
Arrays.sort(arr);
}
//test
public static void printArray(int[] arr){
if(arr==null){
return;
}
for(int i = 0 ; i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
}
//判断是否相等
public static boolean isEqual(int[] arr1,int[] arr2){
if((arr1==null&&arr2!=null)||(arr1!=null&&arr2==null)){
return false;
}
if((arr1==null) && (arr2==null)){
return true;
}
if(arr1.length!=arr2.length){
return false;
}
for(int i =0 ; i <arr1.length;i++){
if(arr1[i]!=arr2[i]){
return false;
}
}
return true;
}
public static void mergeSort(int[] arr){
if(arr==null || arr.length<2 ){
return;
}
mergeSort(arr,0,arr.length-1);
}
public static void mergeSort(int[] arr,int l, int r){
if(l==r){
return;
}
int mid = (l+r)/2;
mergeSort(arr,l,mid);
mergeSort(arr,mid+1,r);
merge(arr,l,mid,r);
}
public static void merge(int[] arr, int l,int mid , int r) {
int[] help= new int[r-l+1];
int i =0 ;
int p1= l ;
int p2 = mid+1;
while (p1<=mid&&p2<=r){
help[i++] =arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
}
while (p1<=mid){
help[i++]=arr[p1++];
}
while (p2<=r){
help[i++] = arr[p2++];
}
for(i = 0 ;i<help.length;i++){
arr[l+i]=help[i];
}
}
}