导读:
归并排序:是采用分治法(Divide and Conquer)。
它的主要思想就是把两个数组(各个一定要有序),归并在一个数组中。
如一个数组要求用归并进行排序,主要要考虑试实现两个部分:
(1)“分解”——如何将一个大的数组逐步分成多个小的有序数组。
(2)“合并”—— 如何将两个有序列表并成一个适当的数组。
则可以两种进行归并:
1. 自顶而下的归并排序
2. 自底而上的归并排序
核心代码:
//归并
public static void merge(Comparable[]a , int lo, int mid, int hi){
//把a的lo-hi复制到aa中,这里未必a的开始结束的引索是从0,到 最后一个索引,用一个辅助数组(必不可少)把要归并数组的复制,此时的数组a[lo,mid], a[mid+1,hi]已经有序。可以进行归并。
Comparable[] aa = new Comparable[a.length];
for(int k = lo; k<=hi; k++){
aa[k] = a[k];
}
//在辅助数组aa中分 左 中 右引索。
int i = lo;//左半开始
int j = mid +1;//由半开始
//其实是对对应的数据lo--hi索引元素拷贝
for(int k =lo; k<=hi; k++){
//分别为4种情况 如图
if(i>mid)
a[k] = aa[j++];
else if(j>hi)
a[k] = aa[i++];
else if(less(aa[i],aa[j]))
a[k] = aa[i++];//aa[i]更小
else
a[k] = aa[j++];
}
}
归并中,比较复制的数组示意图:
1. 自顶而下的归并排序
示意图:
分---直到单个元素为止。然后 逐步合并。
public static void sort(Comparable[] a, int lo, int hi){
//排除错误数组 和 (1)终止递归,出口
if(hi<=lo) return;
//(2)规律
int mid = lo+(hi-lo)/2;
//(3)递归方法
sort(a,lo,mid);
sort(a,mid+1,hi);
merge(a , lo, mid, hi);
}
public static void sort(Comparable[] a){
//步长为1,然后是2,然后是4
for(int sz = 1; sz < a.length; sz = sz+sz){
//内层是从 第一个元素开始,从步长为1(肯定形成有序)开始,元素0 ,1 为一组。 每次循环移动变化为0--->2, 则2,3为一组。规律:0---2;2--4;即:lo+=sz+sz;直到起始元素为a.length-sz,因为它不够归并的。
for(int lo = 0;lo<a.length-sz;lo+=sz+sz){
//lo+sz-1 中间 Math.min(lo+sz+sz-1, a.length-1) 最边,但不能超出a.length-1。
merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1, a.length-1));
}
}