zoukankan      html  css  js  c++  java
  • Algs4-2.3.23Java的排序库函数

    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 ",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 ",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 ",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 ",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 ",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);
        }
    }

  • 相关阅读:
    主线程MainThread与渲染线程RenderThread
    杀死进程的几种方式
    Android App的设计架构:MVC,MVP,MVVM与架构经验谈
    动画完全解析(二):补间动画原理及自定义动画
    SublimeText教程
    JqGrid自定义的列
    js 除法 取整
    js日期字符串增加天数的函数
    Oracle中的rownum和rowid
    jQuery判断对象是否是函数
  • 原文地址:https://www.cnblogs.com/longjin2018/p/9868576.html
Copyright © 2011-2022 走看看