2.2.11改进。实现2.2.2节所述的对归并排序的三项改进:加快小数组的排序速度,检测数组是否已经有序以及通过在递归中交换参数来避免数组复制。
答:归并排序的本质是由两部分组成,一是排序,二是归并。
1)对小数组的排序均发生在a数组中,如果连续对两个小数组进行排序,那么只可能归并到aux,属于a+a->aux。
2)归并后只对一个小数组排序然后归并,那么小数组在这次归并中属于归并段的右半段(右半段指索引大的半段,因为lo+(hi-lo)/2将数组对半时要么两个子数组等长,要么左半边比右半边多1),归并时将aux+a归并到a中,这样就不会在归并过程中破坏a后半段未归并的元素值,属于aux+a->a。
3)归并过程中的两个源数组是同一个数组时,归并的目标数组就是另一个数组,a+a->或aux+aux->a,这样才能保证归并过程中不会破坏未归并的元素值。
4)归并过程中的两个源数组不是同一个数组时,归并的目标数组就是两个源数组中的后半段的那个数组。aux+a->a或a+aux->a。
5)如果连续两连两次进行归并,那么说明第一次归并后的目标数组将作为第二次归并时的右半段源数组,与此右半段对应的左半段数组要么是数组a,要么是数组aux,由于参于归并的两个子数组一定有序,如果a数组的这左半段有序那么参与此次归并的数组的左半段是a,无序那么左半段是aux。
import java.util.Arrays;
public class Merge6
{
private static int subArrayLenTrunONInsertionSort=15;
private static int sortTimes=0;
private static boolean isMerge=false;
private static Comparable[] from1;
private static Comparable[] from2;
private static Comparable[] to;
private static int m;
public static void sort(Comparable[] a)
{
Comparable[] aux=new Comparable[a.length];
sort(a,aux,0,a.length-1);
if (a.length>15)
a=to;
StdOut.printf("isSorted=%s",Merge6.isSorted(a));
}
private static void sort(Comparable[] a,Comparable[] aux,int lo,int hi)
{
//StdOut.printf("lo=%d,hi=%d
",lo,hi);
if ((hi-lo+1)<=subArrayLenTrunONInsertionSort)
{
insertionSort(a,lo,hi);
sortTimes++;
return;
}
int mid=lo+(hi-lo)/2;
isMerge=false;
sort(a,aux,lo,mid);
isMerge=false;
sort(a,aux,mid+1,hi);
if (sortTimes==1)
{
from1=aux;
from2=a;
to=a;
sortTimes=0;
}
else if (sortTimes==2)
{
from1=a;
from2=a;
to=aux;
sortTimes=0;
}
//if(!less(a[mid+1],a[mid])) return;
// for(int i=lo;i<=hi;i++)
// {
// StdOut.printf("from=%.2f,to=%.2f
",from[i],to[i]);
// }
if(isMerge)
{
m=lo+(hi-lo)/2;
// StdOut.printf("m1=%d
",m);
m=lo+(m-lo)/2;
//StdOut.printf("lo=%d,m=%d,hi=%d
",lo,m,hi);
// StdOut.printf("a[m-1]=%.2f,a[m]=%.2f,a[m+1]=%.2f
",a[m-1],a[m],a[m+1]);
if (!less(a[m],a[m-1]) && !less(a[m+1],a[m]))
from1=a;
else
from1=aux;
from2=to;
if (Arrays.equals(from1,from2) && Arrays.equals(from1,a))
to=aux;
else if (Arrays.equals(from1,from2) && Arrays.equals(from1,aux))
to=a;
else if (!Arrays.equals(from1,from2) && Arrays.equals(from2,a))
to=a;
else if (!Arrays.equals(from1,from2) && Arrays.equals(from2,aux))
to=aux;
}
isMerge=true;
/*
if (Arrays.equals(from1,a)) StdOut.printf("a+");
if (Arrays.equals(from1,aux)) StdOut.printf("aux+");
if (Arrays.equals(from2,a)) StdOut.printf("a ");
if (Arrays.equals(from2,aux)) StdOut.printf("aux ");
if (Arrays.equals(to,a)) StdOut.printf("->a ");
if (Arrays.equals(to,aux)) StdOut.printf("->aux
");
*/
merge(from1,from2,to,lo,mid,hi);
}
private static void merge(Comparable[] from1,Comparable[] from2,Comparable[] to,int lo,int mid,int hi)
{
int i=lo;
int j=mid+1;
for(int k=lo;k<=hi;k++)
{
if (i>mid) to[k]=from2[j++];
else if (j>hi) to[k]=from1[i++];
else if (less(from2[j],from1[i])) to[k]=from2[j++];
else to[k]=from1[i++];
}
}
private static boolean less(Comparable v,Comparable w)
{
return v.compareTo(w)<0;
}
private static void exch(Comparable[] a,int i,int j)
{
Comparable t=a[i];
a[i]=a[j];
a[j]=t;
}
private static void insertionSort(Comparable[] a,int lo,int hi)
{
for (int i=lo+1;i<=hi;i++)
for (int j=i;j>lo && less(a[j],a[j-1]);j--)
exch(a,j,j-1);
}
public static boolean isSorted(Comparable[] a)
{
for(int i=1;i<a.length;i++)
if(less(a[i],a[i-1])) return false;
return true;
}
public static void main(String[] args)
{
Integer N=Integer.parseInt(args[0]);
Double[] a=new Double[N];
for(int i=0;i<N;i++)
a[i]=StdRandom.uniform();
Merge6.sort(a);
}
}
参考资料:
Algs3-C语言版Page219
Algs4-Java语言版Page175