码迷,mamicode.com
首页 > 编程语言 > 详细

Algs4-2.3.23Java的排序库函数

时间:2018-10-29 10:23:46      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:rgs   指针   shu   切换   排列   i++   als   比较   tor   

2.3.23Java的排序库函数。在练习2.3.22的代码中使用Tukey‘s ninther方法来找出切分元素--选择三组,每组三个元素,分别取三组元素的中位数,然后取三个中位数的中位数作为切分元素,且在排序小数组时切换到插入排序。
public class E2d3d23
{
    public static void sort(Comparable[] a)
    {
      StdRandom.shuffle(a);
      sort(a,0,a.length-1);
    }
   
    private static void sort(Comparable[] a,int lo,int hi)
    {
        //数组少于M个元素时使用插入排序
        int M=8;
        if (hi-lo+1<M)
        {
            InsertSort(a,lo,hi);
            return;
        }
        //p的初值为lo+1,满足lo~p-1的元素=v
        //i的初值为lo+1,p~i-1为0长,满足p~i-1的元素<v
        //q的初值为hi,q+1~hi为0长,满足q+1~hi的元素=v
        //j的初值为hi,j+1~q为0长,满足q+1~hi的元素>v
        int p=lo+1,i=lo+1,q=hi,j=hi;
       // StdOut.printf("lo=%d,i=%d,j=%d,hi=%d\n",lo,i,j,hi);
        int newVIndex=TukeysNintherIndex(a,lo,hi,M);
        exch(a,lo,newVIndex);
        Comparable v=a[lo];
       
        while(i<=j)
        {
            //当i<j时一定需要i位置元素与v对比,当出现数组只有两个元素v,<v时,i=j,此时如果不进行对比排序后的结果就无序的,所以i=j时也需要对比。
            //由于i=j时还需要对比,那么可能会出现i越过j形成i>=j的情况。
            while(i<=j)
            {
              int cmp=a[i].compareTo(v);
              //StdOut.printf("ToRight i=%d,j=%d,cmp=%d,a[i]=%f,v=%f\n",i,j,cmp,a[i],v);
              //当i位置元素<v时,i向右移动一个位置,此时p~i-1的元素<v
              if (cmp<0) i++;
              //当i位置元素=v时,交换i,p位置的元素,i,p指针向右移动一个位置,此时lo~p-1的元素=v,p~i-1的元素<v
              else if (cmp==0) exch(a,i++,p++);
              //当位置i的元素>v时,i指针暂停右移
              else if(cmp>0) break;
            }
            //当i<j时一定需要j位置元素与v对比,
            //当出现数组只有两个元素v,>v时,i=j,由于在上一个while中i位置元素已与v进行过对比,如果j位置元素再与v进行一次对比就多比较一次了,所以j位置元素与v的比较必要性不强。
            //所以i=j时可以不进行对比了,那么意味着j向左移动时不可能会越过i位置形成i>j的情况,最多只可能是形成i=j的情况。
            while(i<j)
            {
              int cmp=a[j].compareTo(v);
             // StdOut.printf("ToRight i=%d,j=%d,cmp=%d,a[i]=%f,v=%f\n",i,j,cmp,a[i],v);
              //当j位置元素<v时,j指针暂停左移
              if (cmp<0) break;
              //当j位置元素=v时,交换j,q位置的元素,j,q指针向左移动一个位置,此时q+1~hi的元素=v,j+1~q的元素>v
              else if(cmp==0) exch(a,j--,q--);
              //当j位置元素>v时,j向左移动一个位置,此时j+1~q的元素>v
              else if(cmp>0)j-- ;
            }
            //i,j指针相遇或i越过j时形成i>=j的几种具体排列
            //1)v,<v 此情况时i>j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //2)v,v,此情况时i>j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //3)v,>v,此情况时i=j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //4)v,>v,<v此情况时i<j需要交换i,j位置元素,并将i,j向前移动一位,此时i>j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
            //5)v,<v,>v此情况时i=j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。
           
            //当i,j 指针相遇或越过时,结束本轮比较
            if (i>=j) break;
            //StdOut.printf("Exch i=%d,j=%d\n",i,j);
            //上述第4点。
            exch(a,i,j);
            i++;
            j--;
        }
        //依据上述5点的结论,得出位置i和i右边的元素>=v,保存i到j
        j=i;
        //左端=v元素与<v的元素段的右边交换。具体
        //从左端向右将所有=v的元素与i-1位置到左边的元素交换,
        //lo~i-1段,p无论是靠左或靠右或均分此段时,这种交换都将得到<v,=v的排列。
        i--;
        for (int k = lo; k < p; k++) exch(a, k, i--);
        //右端=v端元素与>v的元素段的左端进行交换。
        //从右端向左将所有=v的元素与j位置到右边的元素交换,
        //j~hi段,q无论是靠左或靠右或均分此段时,这种交负都将得到=v,>v的排列。
        for (int k = hi; k > q; k--) exch(a, k, j++);
      // StdOut.printf("Move lo=%d,i-1=%d,j+1=%d,hi=%d\n",lo,i-1,j+1,hi);
      // StdOut.println("Left Sort");
        //对<v的左子数组再排序,此时i处在最右边的<v的位置上。
       sort(a, lo, i);
       //StdOut.println("Right Sort");
       //对>v的右子数组再排序,此时j处在最左边的>v的位置上。
       sort(a, j, hi);
    }
   

     //返回Tukey‘s ninther取样切分元素索引
    private static int TukeysNintherIndex(Comparable[] a,int lo,int hi,int M)
    {
        //子数组少于4M个元素时,第一个元素作为切分元素
        if((hi-lo+1)<4*M)  return lo;
        //子数组有4M个或以上元素时,取三个子数组中的中位数的中位数作为切分元素
       
        ////取第一个子数组
        Integer[] firstArr={lo,lo+M/2,lo+M};
        ////按原数组的值对新数组进行排序。排序后的结果是原数组小中大值对应的索引
        if(less(a[firstArr[1]],a[firstArr[0]])) exch(firstArr,0,1);
        if(less(a[firstArr[2]],a[firstArr[1]])) exch(firstArr,1,2);
        if(less(a[firstArr[1]],a[firstArr[0]])) exch(firstArr,0,1);

         ////取第二个子数组
        Integer[] secondArr={(hi-lo)/2-M/2,(hi-lo)/2,(hi-lo)/2+M/2};
        ////按原数组的值对新数组进行排序。排序后的结果是原数组小中大值对应的索引
        if(less(a[secondArr[1]],a[secondArr[0]])) exch(secondArr,0,1);
        if(less(a[secondArr[2]],a[secondArr[1]])) exch(secondArr,1,2);
        if(less(a[secondArr[1]],a[secondArr[0]])) exch(secondArr,0,1);

         ////取第三个子数组
        Integer[] thirdArr={hi-M,hi-M/2,hi};
        ////按原数组的值对新数组进行排序。排序后的结果是原数组小中大值对应的索引
        if(less(a[thirdArr[1]],a[thirdArr[0]])) exch(thirdArr,0,1);
        if(less(a[thirdArr[2]],a[thirdArr[1]])) exch(thirdArr,1,2);
        if(less(a[thirdArr[1]],a[thirdArr[0]])) exch(thirdArr,0,1);
 
        ////取三个数组中位数的中位数
        Integer[] midArr={firstArr[1],secondArr[1],thirdArr[1]};
        ////按原数组的值对新数组进行排序。排序后的结果是原数组小中大值对应的索引
        if(less(a[midArr[1]],a[midArr[0]])) exch(midArr,0,1);
        if(less(a[midArr[2]],a[midArr[1]])) exch(midArr,1,2);
        if(less(a[midArr[1]],a[midArr[0]])) exch(midArr,0,1);
    
        return midArr[1];
    }
   
    private static void InsertSort(Comparable[] a,int lo,int hi)
    {
        for (int i=lo+1;i<hi+1;i++)
        {
            for (int j=i;j>0 && less(a[j],a[j-1]);j--)
                exch(a,j,j-1);
          }
    }
       
    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 show(Comparable[] a)
    {
        for (int i=0;i<a.length;i++)
            StdOut.print(a[i]+" ");
        StdOut.println();
    }
   
    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)
    {
        int N=Integer.parseInt(args[0]);
        Double[] a=new Double[N];
        StdOut.println(a.length);
        for(int k=0;k<N;k++)
            a[k]=StdRandom.random();

        sort(a);

        StdOut.println("isSorted=" +isSorted(a));
       // show(a);
    }
}

Algs4-2.3.23Java的排序库函数

标签:rgs   指针   shu   切换   排列   i++   als   比较   tor   

原文地址:https://www.cnblogs.com/longjin2018/p/9868576.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!