基本思路:
1.整体分为分 - 治
2.分,怎么分?通过递归向下分,到只有两个数比较为止
3.治,如何治?递归回溯向上合并,在分到最底部开始,
a.比较两个数大小,并使用一个临时数组temp临时储存
b.如果两个序列(最少有1个值)比较完,一方序列还有值,就将剩余的全部放到临时数组temp
c.将临时数组的值再copy到原数组
上图:
下面这张图是回溯上去后最后一次合并,并不是只有一次合并
再来看上图,这次排序其实有数组长度-1次合并,分别是8 4,5 7,1 3,6 2,48 57,13 26以及下面图中的最后一次合并 4578 1236
结合代码分析,再看不明白可以自己debug走几遍就清晰了
//拆分在合并
public static void diguisort(int left,int right,int nums[],int temp[]){
if (left<right){
int mid=(left+right)/2;
// 向左递归
diguisort(left,mid,nums,temp);
// 向右递归
diguisort(mid+1,right,nums,temp);
guisort(left,mid,right,nums,temp);
}
}
// 合并方法
public static void guisort(int left,int mid,int right,int nums[],int temp[]){
// 左边序列的初始值
int l=left;
// 右边序列的初始值
int r=mid+1;
// 因为我们比较两个序列会把小的值暂存另一个数组,所以要有这个计数器
int t=0;
// (1) 左右两边值的比较
while (l<=mid && r<=right){
// 左小于右
if (nums[l]<=nums[r]){
// 左值赋给暂存数组
temp[t]=nums[l];
// 暂存数组后移
t+=1;
// 左序列后移
l+=1;
}else{
temp[t]=nums[r];
t+=1;
r+=1;
}
}
// (2) 如果有一方剩余数组将剩余数组全部放到暂存数组
// 左边序列有剩余
while (l<=mid){
temp[t]=nums[l];
t+=1;
l+=1;
}
// 右边序列有剩余
while (r<=right){
temp[t]=nums[r];
t+=1;
r+=1;
}
// 将temp数组copy到原数组
t=0;
int templeft=left;
// System.out.println("templeft:"+templeft+" "+"right:"+right);
while (templeft<=right){
nums[templeft]=temp[t];
t+=1;
templeft+=1;
}
}
我们再来测试一波:
int num[]=new int[800000];
int temp[]=new int[num.length];
for (int i = 0; i <num.length; i++) {
num[i] = (int) (Math.random() * 800000);
}
// 测试
Date d1 = new Date();
SimpleDateFormat s = new SimpleDateFormat("YY-MM-DD HH:mm:ss:SSS");
String s1 = s.format(d1);
System.out.println("排序前的时间;" + s1);
diguisort(0, num.length-1,num,temp);
// System.out.println(Arrays.toString(num));
Date d2 = new Date();
String s2 = s.format(d2);
System.out.println("排序后时间;" + s2);
80w数据不到200ms,跟我一样快!!!