Algs4-2.2.12次线性的额外空间O(N^2)时间复杂度

2.2.12次线性的额外空间。用大小M将数组分为N/M块(简单起见,设M是N的约数)。实现一个归并方法,使之所需的额外空间减少到max(M,N/M):(i)可以先将一个块看做一个元素,将块的第一个元素作为块的主键,用选择排序将块排序;(ii)遍历数组,将第一块和第二块归并,完成后将第二块和第三块归并,等等。
答:一个O(N^2)时间复杂度,O(M)空间复杂度的算法。
1)将a划分成N/M个单个长度最长为M的子数组,对每个子数组使用归并排序算法排序。

2)将a划分成N/M个单个长度最长为M子数组,以每个子数组的第一个元素作为排序关键字,使用选择排序算法将各个子数组排序。对N/M个子数组排序,在归并时会因归并的两段已有序而不用再归并。

3)归并子数组1和子数组2,再归并子数组1~2和子数组3,再归并子数组1~3和子数组4,直到归并完子数组1~(N/M-1)和子数组N/M。例如下现的情况(2,20,30)(3,5,8)(4,6,10),归并前两个后为(2,3,5)(8,20,30)(4,6,10),此时若只归并后面两个子组数,归并后的结果是(2,3,5)(4,6,8)(10,20,30)此时是无序的。如果在子数组1,2归并后,再将1,2与子数组3归并,得到的结果(2,3,4)(5,6,8)(10,20,30)才有序,所以此种采用了后段与所有前段归并的方式,也因此形成O(N^2)时间复杂度,但也可以看成是O((N/M)^2)时间复杂度。

4)如果归并的两段的交界值有序,那么跳过本次归并,无序时归并这两段。然后进行下一段与所有前段的归并。归并时先将后段长度为M的子数组复制到辅助数组aux,然后将前段和辅组数组进行归并,两段中的大值从数组a的右边归并到左边。
图片

public class E2d2d12
{
    public static void sort(Comparable[] a,int M)
    {
       int N=a.length;
       Comparable[] aux=new Comparable[M];
       //sort each block elements, block size is 2*M
       for(int lo=0;lo<N;lo=lo+M)
           sort(a,aux,lo,lo+M-1);
       //sort all blocks with block first element
       SelectionSortBlock(a,M);
       //Merge
       for(int j=1;j<N/M;j++)
       {
           if (!less(a[j*M],a[j*M-1])) continue;
           Merge(a,aux,0,j*M-1,(j+1)*M-1);
       }
   }
   
    private static void sort(Comparable[] a,Comparable[] aux,int lo,int hi)
    {
        if (hi<=lo) return;
        int mid=lo+(hi-lo)/2;
        sort(a,aux,lo,mid);
        sort(a,aux,mid+1,hi);
        if (!less(a[mid+1],a[mid])) return;
        Merge(a,aux,lo,mid,hi);
    }
  
    //merge bigger value to the maxIndex of array a.
    private static void Merge(Comparable[] a,Comparable[] aux,int lo,int sp,int hi)
    {
        int M=hi-sp;
        //copy right half of array a to aux
        for(int i=0;i<M;i++)
            aux[i]=a[sp+1+i];
        //merge from array aux with left half  of a to  a
        int auxTop=M-1;
        int aTop=sp;
        for(int k=hi;k>=lo;k--)
        {
            if(auxTop<0) a[k]=a[aTop--];
            else if (aTop<lo) a[k]=aux[auxTop--];
            else if(less(aux[auxTop],a[aTop])) a[k]=a[aTop--];
            else a[k]=aux[auxTop--];
        }
    }
   
   private static void SelectionSortBlock(Comparable[] a,int M)
    {
        int length=a.length;
        int minIndex;
        for(int i=0;i<length;i=i+M)
        {
            minIndex=i;
            for(int j=i+M;j<length;j=j+M)
               if(less(a[j],a[minIndex])) minIndex=j;
            exch(a,i,minIndex,M);     
         }       
    }

      
    private static boolean less(Comparable v,Comparable w)
    {
        return v.compareTo(w)<0;
    }
   
     private static void exch(Comparable[] a,int i,int j,int length)
    {
        Comparable t;
        for(int index=0;index<length;index++)
        {
            t=a[i+index];
            a[i+index]=a[j+index];
            a[j+index]=t;
        }
    }
   
     public static boolean isSorted(Comparable[] a)
    {
        int len=a.length;
        for(int i=1;i<len;i++)
            if (less(a[i],a[i-1])) return false;
        return true;
    }
       
    public static void main(String[] args)
    {
        int N=Integer.parseInt(args[0]);
        int M=Integer.parseInt(args[1]);
        Double[] a=new Double[N];
        for(int i=0;i<N;i++)
            a[i]=StdRandom.uniform();
        sort(a,M);
        StdOut.printf("isSorted=%s",isSorted(a));
    }
}
问题中的max(M,N/M)没有用到、将第一块和第二块归并,完成后将第二块和第三块归并等等没有用到,块排序对第一块和第二块,第二块对第三块的归并的意义有没有可能是将时间复杂度降底到O(NlgN)的一个前提保证?如果是应该怎么使用?很遗憾,但是下面的内容说明有更好的时间复杂度算法。 图片

posted @ 2018-10-27 09:10  修电脑的龙生  阅读(478)  评论(0编辑  收藏  举报