快速排序quickSort的深入学习-19.9.8-13

梳理:荷兰国旗问题+快排

一、

题目1:给定一个num,把一个数组小于等于num的放在左边,大于num的放在右边,返回分界点。

package Algothrims;
public class heLangFlag {
     
     static int arr[]= {4,7,8,3,6,2,1,9,10,5};
          
     public static void partition(int[] arr,int l,int  r,int num){
          int i,j;
          int less=-1;//小于区域指针
          
          for(i=l;i<r;i++) {     //一轮过后能得到小于区域和大于区域的交界索引x;
              if(arr[i]<num) {
                   swap(arr,less+1,i);
                   less++;  
              }    
          }
          for(i=0;i<10;i++) {
              System.out.print(arr[i]+" ");
          }
          System.out.println("less="+less);
     }
     public static void main(String[] args) {
          
         partition(arr,0,9,5);       
          
     }    
     public static void swap(int[] arr,int l,int r){
          int t;
          t=arr[l];
          arr[l]=arr[r];
          arr[r]=t;
     }
}
// 4 3 2 1 5 8 7 9 10 6 less=4

题目2:荷兰国旗问题:把数组中小于num的放左边,等于num的放中间,大于num的放右边。

package Algothrims;
public class heLangFlagII {
     static int arr[]= {4,5,5,3,6,7,1,9,10,5};
     
     public static void partition(int[] arr,int l,int  r,int num){
          int less=l-1;//小于区域指针
          int more=r+1;//大于区域指针
          int cur = l; //当前指针
          while(cur < more) {
              if(arr[cur]<num) {
                   swap(arr,++less,cur++);
              }
              else if(arr[cur]>num) {
                   swap(arr,--more,cur);
              }
              else cur++;
          }
          for(cur=0;cur<10;cur++) {
              System.out.print(arr[cur]+" ");
          }
          System.out.print("less="+less+"   "+"more="+more);
     }
     
     public static void main(String[] args) {
          
          partition(arr,0,9,5);   
     }
     public static void swap(int[] arr,int l,int r){
          int t;
          t=arr[l];
          arr[l]=arr[r];
          arr[r]=t;
     }
}
//4 3 1 5 5 5 9 10 7 6 less=2  more=6

 

1. 经典快排

经典快排:将数组中最后的数作为x,把小于等于x的数放在左边,大于x放在右边,然后左右两部分分别递归。

2.荷兰国旗思路改进经典快排

将小于num的放左边,等于 mum放中间,大于区域放右边。省去了等于部分的遍历操作

codding……java

package Algothrims;
public class heLangFlagII {
     static int arr[]= {4,5,5,3,6,7,1,9,10,5};
     
     public static void quickSort(int[] arr) {
          if (arr == null || arr.length < 2) {
              return;
          }
          quickSort(arr, 0, arr.length - 1);
     }
     public static void quickSort(int[] arr, int L, int  R) {
          if (L < R) {
              //swap(arr, L + (int) (Math.random() * (R - L + 1)), R);//随机快排
              int[] p = partition(arr, L, R);
              quickSort(arr, L, p[0]);
              quickSort(arr, p[1] , R);
          }
     }
     
     public static int[] partition(int[] arr,int L,int  R){
          int less = L-1;//小于区域指针
          int more = R;  //大于区域指针-->注意点1:最后一个数不参与交换
          int cur = L; //当前指针
          
          while(cur < more) {
              if(arr[cur]<arr[R]) {
                   swap(arr,++less,cur++);
              }
              else if(arr[cur]>arr[R]) {
                   swap(arr,--more,cur);
              }
              else cur++;
          }
          swap(arr,more,R);   //注意点2:因为我们的初始more是最后一个位置,意味着最后一个数是不参与交换的,所以在while结束后,因为前面的数都比它大,所以把该数与大于区域第一个数交换
          return new int[] { less , more+1 };
     }
     
     public static void main(String[] args) {
          
          quickSort(arr);    
     
          for(int i=0; i<10; i++) {
              System.out.print(arr[i]+" ");
          }         
     }
     public static void swap(int[] arr,int l,int r){
          int t;
          t=arr[l];
          arr[l]=arr[r];
          arr[r]=t;
     }
}

 

 

       分析:现在我们需要从小到大排序,而数据是9,8,7,6,5,4,3,2,1,0;经典排序的时间复杂度就会变成O(n2), 跟数据分布有很大的关系。最好O(Nlog2N),    最坏:有序数据—O(n2),  平均:O(Nlog2N) 

 

 

3. 随机快排

上3中,把注释打开就是一个随机快排

随机快排: 长期期望复杂度——O(NlogN),代码简单,常数项简单,很常用。该复杂度是经过数学证明的,我暂不做了解。

 

二、

  1. 快排《啊哈算法》的描述以及注意点

      /*
          * 快速排序-两边一起走
          * 以首或者尾作为key
          * 问题1:以首元素为key时,为什么一定要注意从右边开始移动?
               *   问题2:为什么左边的i=left+1会出问题?因为如果最后只剩两个数据,i就直接等于j,这就失去了意义。
          */
         public void quickSort(int left,int right) {
         int i=left;  //i=left+1
         int j=right;
         long temp;
         long key=arr[left];
         
         if(left>=right)
              return;
         
         while(i!=j)  //不等于退出,下面直接做交换
         {
              while(arr[j]>=key && i<j)
                  j--;
              while(arr[i]<=key && i<j)
                  i++;      
              
              //交换i,j索引数据
              temp = arr[i];
              arr[i] = arr[j];
              arr[j] = temp;
         }
         
         arr[left] = arr[i];
         arr[i] = key;
    
         quickSort(i+1,right);
         quickSort(left,i-1);
      }
    
    
              /**
               * 问题1:为什么key设为首值时,一定要右边先行
               * 对这个程序来说,key设为最左边,是大区域往左走的趋势,所以j先开始
               *     如果中间区域是小与key的,那么i=j之后交换
               *     如果中间区域大于key的,继续往左走,大区域范围扩大。
               * 如果key设为最右边,那么是小于区域往右扩大的趋势,从i先开始
               * 为什么有这样的划分?那是因为这个程序在处理最后i=j的时候是要注意的。
    
               * 前面已经设置了优先次序,所以最后可以这样直接处理。但这个不够通用?
               * 如果我们把key的值设为随机,或者中间呢?
               */

    上述问题1的分析:上面的如果没有解释清楚可以仔细阅读下面的这个演示过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值