美文网首页
快速排序 优化与总结

快速排序 优化与总结

作者: Mereder | 来源:发表于2019-04-23 12:23 被阅读0次

    快速排序的总结和优化

    1. 基础快排

      快排的基本框架就是下边这样。更鲁棒一点的话,还需要考虑传入的array是否是非法参数。

      此处优化:应当将数组,打乱顺序,如果数组基本有序,快排的时间复杂度将退化到O(n^2 )

      应该在传入sort之前就将数组 shuffle。

      public static void sort(int[] array,int lo ,int hi){
          if (array == null || lo < 0 || hi > array.length - 1) {
                  throw new IllegalArgumentException("Invalid Parameters");
              }
          if(lo>=hi){
               return ;
           }
           int index=partition(array,lo,hi);
           sort(array,lo,index-1);
           sort(array,index+1,hi); 
      }
      

      shuffle

      public static void shuffle(int a[]){
           int n = a.length;
           for (int i = n; i > 0 ; i--) {
               int index =(int)(Math.random()*i);
               swap(a,index, i-1);
           }
       }
      

      完整测试快排过程

      public static void main(String[] args) {
           int a[] = {1,2,3,4,5,6,7,8};
           int len = a.length;
           shuffle(a);
           sort(a,0,len-1);
           for (int i = 0; i < len; i++) {
                 System.out.println(a[i]);
           }
      }
      
    2. 重点是 partition

      《算法》第四版给的partition如下:

      ​ 存在问题,当数字仅有一个数字的时候,a[++i]越界了。并不鲁棒,所以使用这个之前需要单独处理数组只有一个数字的测试。

          public static int partition(int []a,int lo,int hi){
              int i = lo;
              int j = hi + 1;
              while(true){
                  // 若一趟有序则 退出
                  while(a[++i] < a[lo]) if (i == hi) break;
                  while(a[--j] > a[lo]) if( j == lo) break;
                  if (i >= j) break;
                  swap(a,i,j);
              }
              swap(a,lo,j);
              return j;
          }
      

      较为鲁棒的写法(而且不使用swap 进行交换)

      public static int partition(int []a,int lo,int hi){
              int key=a[lo];
              while(lo<hi){
                  while(array[hi]>=key&&hi>lo){
                      hi--;
                  }
                  array[lo]=array[hi];
                  while(array[lo]<=key&&hi>lo){
                      lo++;
                  }
                  array[hi]=array[lo];
              }
              array[hi]=key;
              return hi;
          }
      

      上面方法避免了数组仅有一个数字的时候的越界问题,但是不够优化,因为我们默认选lo 作为我们的枢值,然后进行划分的。

      进一步优化的方法是,枢值的选取应该也是随机的。这个随机是在lo~hi之间随机选一个来进行。

          public static int partition(int []a,int lo,int hi){
              // math.random 返回[0.0,1.0)的double 值
              int index = lo + (int)(Math.random()*(hi-lo+1));
              swap(a,lo,index);
              int key = a[lo];
              while(lo < hi ){
                  while(a[hi] > key && hi > lo){
                      hi--;
                  }
                  a[lo] = a[hi];
                  while(a[lo] < key && hi > lo){
                      lo++;
                  }
                  a[hi] = a[lo];
              }
              a[hi] = key;
              return hi;
          }
      

      最优化的方法是 :三数取中间的数 来当 基准点

          public int partition(int a[],int lo,int hi){
              int mid = lo+(hi-lo)>>1;
              // 让mid 是 介于  a[hi] 和 a[lo] 之间的数
              if (a[mid] > a[hi]) swap(a,mid,hi);
              if(a[mid] < a[lo]) swap(a,mid,lo);
              // 此时确保a[lo] < a[mid] < a[hi] 再将mid交换给  lo 
              // 此时lo 为 lo  mid  hi 中的 中值
              if (a[mid] > a[lo]) swap(a,mid,lo);
              int key = a[lo];
              while(lo < hi){
                  while(a[hi] > key && hi > lo ) hi--;
                  a[lo] = a[hi];
                  while(a[lo] < key && hi > lo) lo++;
                  a[hi] = a[lo];
              }
              a[hi] = key;
              return hi;
          }
      

    相关文章

      网友评论

          本文标题:快速排序 优化与总结

          本文链接:https://www.haomeiwen.com/subject/tqcvgqtx.html