我是一个从汽车行业转行IT的项目经理,我是Edward。今天我们聊聊归并排序,merge sort是一个很有用的排序,无论是在Java的Arrays.sort算法还是针对对象的Collection.sort里都有应用,不过Collection.sort用到的是归并排序的优化版,Tim-sort。Tim-sort整体上是一种多路归并排序,用到了二分插入和优化归并,,但是细节方面有很多雕琢。
归并排序的写法分为三个步骤:
- 1.首先特别设立一个左右两边等长且两边都有序的实验数组,写一个merge算法满足排序 建议:int[]arr= {1,3,4,8,9,2,5,6,7};
- 2.将merge算法的各局部变量设置成函数的传入参数,增强算法的灵活性(但是注意截取的实验数组还是要两边等长且有序)
- 建议:merge(arr,0,5,8);
- 3.用递归思想完成sort内的算法
package algorithm;
/**
* 归并排序:
* 1.首先特别设立一个左右两边等长且两边都有序的实验数组,写一个merge算法满足排序
* 2.将merge算法的各局部变量设置成函数的传入参数,增强算法的灵活性
* (但是注意截取的实验数组还是要两边等长且有序)
* 3.用递归思想完成sort内的算法
* @author EP
* @date 2020年4月8日
* @version 1.0
*/
public class MergeSort {
public static void main(String[] args) {
int[]arr= {1,3,4,8,9,2,5,6,7};
sort(arr,0,arr.length-1);
print(arr);
}
public static void sort(int[]arr,int left,int right) {
//1.设置递归的base case
if (left==right) {
return;
}
//2.分别排两边
int mid = left+(right-left)/2;
sort(arr,left,mid);
sort(arr,mid+1,right);
//3.合并
merge(arr, left, mid+1,right);
//merge(arr)
//merge(arr,0,5,8);
}
static void merge(int[]arr,int leftPtr, int rightPtr, int rightBound) {
int mid = rightPtr-1;
int []temp = new int[rightBound-leftPtr+1];
int i = leftPtr, j = rightPtr, k=0;
while (i<=mid&&j<=rightBound) {
temp[k++]= arr[i]<=arr[j] ? arr[i++]:arr[j++];
}
while (i<=mid) {
temp[k++]=arr[i++];
}
while (j<=rightBound) {
temp[k++]=arr[j++];
}
//不要忘了把temp数组复制到arr中
for (int m = 0; m < temp.length; m++) {
arr[leftPtr+m]=temp[m];
}
}
static void print(int[]arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
再用对数期验证一下:
package algorithm;
import java.util.Arrays;
import java.util.Random;
/**
* 马士兵亲授
* 验证算法——对数器
* @author EP
* @date 2020年4月3日
* @version 1.0
*/
public class DataChecker {
static int [] generateRandomArray() {
Random r = new Random();
int[]arr=new int[10000];
for (int i = 0; i < arr.length; i++) {
arr[i]=r.nextInt(10000);
}
return arr;
}
static void check() {
int[]arr=generateRandomArray();
int[]arr2=new int[arr.length];
System.arraycopy(arr, 0, arr2, 0, arr.length);
long start = System.currentTimeMillis();
Arrays.sort(arr);
long end = System.currentTimeMillis();
System.out.println("Arrays.sort耗时:"+(end-start)+"ms");
start = System.currentTimeMillis();
MergeSort.sort(arr2, 0, arr2.length-1);
//ShellSortKnuth.sort(arr2);
end = System.currentTimeMillis();
System.out.println("Mysort耗时:"+(end-start)+"ms");
// start = System.currentTimeMillis(); //希尔排序Knuth优化版的小测试
// ShellSort.sort(arr);
// end = System.currentTimeMillis();
// System.out.println("sort耗时:"+(end-start)+"ms");
boolean same = true;
for (int i = 0; i < arr2.length; i++) {
if (arr[i]!=arr2[i]) {
same=false;
}
}
System.out.println(same==true?"right":"wrong");
}
public static void main(String[] args) {
check();
}
}
结果是right,没有问题,而且速度还是相当快的,基本上跟Arrays.sort的速度相当。