2.2.16自然的归并排序。编写一个自底向上的归并排序,当需要将两个子数组排序时能够利用数组中已经有序的部分。首先找到一个有序的子数组(移动指针直到当前元素比上一个元素小为止),然后再找出另一个并将它们归并。根据数组大小和数组中递增子数组的最大长度分析算法的运行时间。
import java.util.Arrays;
public class E2d2d16
{
public static void sort(Comparable[] a)
{
int N=a.length;
if(N<=1) return;
Comparable[] aux=new Comparable[N];
int lo=0;
int sp=-1;
int hi=0;
while(!(lo==0 && sp==N-1))
{
lo=0;
while(lo<N-1)
{
sp=FindAscIndex(a,lo);
hi=FindAscIndex(a,sp+1);
if(sp==hi)
break;
else
{
merge(a,aux,lo,sp,hi);
lo=hi+1;
}//end if
}//end while
}//end while
}
private static int FindAscIndex(Comparable[] a,int lo)
{
int N=a.length;
if (lo==N-1) return lo;
else if(lo>N-1) return lo-1;
int i;
for(i=lo+1;i<N && !less(a[i],a[i-1]);i++);
return i-1;
}
private static void merge(Comparable[] a,Comparable[] aux,int lo,int sp,int hi)
{
for(int i=lo;i<=hi;i++)
aux[i]=a[i];
//
int i=lo;
int j=sp+1;
for(int k=lo;k<=hi;k++)
{
if(i>sp) a[k]=aux[j++];
else if(j>hi) a[k]=aux[i++];
else if(less(aux[j],aux[i])) a[k]=aux[j++];
else a[k]=aux[i++];
}
}
public static boolean isSorted(Comparable[] a)
{
int N=a.length;
for(int i=1;i<N;i++)
if(less(a[i],a[i-1])) return false;
return true;
}
private static boolean less(Comparable v,Comparable w)
{
return v.compareTo(w)<0;
}
public static void main(String[] args)
{
Integer N=Integer.parseInt(args[0]);
Comparable[] a =new Comparable[N];
for(int i=0;i<N;i++)
a[i]=StdRandom.uniform();
sort(a);
StdOut.printf("a size is:%d,a is sorted=%s",a.length,isSorted(a));
}
}
分析:
最坏情况:数组为逆序时,可以确保参与第一轮的归并的所有子数组的长度均为1,时此即为最坏情况。设数组长度为N=2^n,那么归并树深度为n,每一层查找子数组需要进行2N次数组访问,每一层归并需要2N次数组访问完成复制到辅助数组的操作,需要2N次数组访问完成比较,需要2N次访问完成辅助数组到a数组的复制,那么从底向上的自然归并最坏情况下需要访问8NlgN次数组。
最长子数组为k时:数组的最长子数组为k时,的最好情况是第一轮的所有子数组的长度均为k,设数组长度为N=K*2^m,那么归并树深库为m,每一层查找子数组需要进行2N次数组访问,每一层归并需要2N次数组访问完成复制到辅助数组的操作,需要2N次数组访问完成比较,需要2N次访问完成辅助数组到a数组的复制,那么从底向上的自然归并最坏情况下需要访问8Nlg(N/k)次数组操作。
转载于:https://www.cnblogs.com/longjin2018/p/9860101.html