快速排序的优化

  在个人上一篇博客中(https://www.cnblogs.com/algorithm-process/p/11963856.html),咱们提到了快速排序划分的三钟方法,在快速排序中,咱们但愿对序列进行划分时,能将一个序列进行两等分,可是咱们在使用时始终选取第一个元素为基准值,这样就会致使在一些状况(好比是降序排列的序列)下,没法将序列进行等分或是近似等分。若是咱们每次选择基准值是一个中间值是否是能尽量的将待排序的序列作到一个趋近于等分的状况呢?接下来就是由这种思想而提出的优化方法。html

 三点中值法

  思想:在左边界p,右边界r和中间下标mid所表明的元素之间选择一个做为基准点,选择方法为找到这三个值中中间那个做为基准点。数组

  代码以下:优化

 1 int partition(int a[],int p,int r){
 2     //选取一个基准点 
 3     int midIndex= p+((r-p)>>1);//中间下标
 4     int midValue=-1;//中间值下标
 5     if(a[p]<=a[midIndex]&&a[p]>=a[r]) midValue=p;
 6     else if(a[r]<=a[midIndex]&&a[r]>=a[p]) midValue=r;
 7     else midValue=midIndex;
 8     swap(a[midValue],a[p]);
 9     
10     int x=a[l];//基准点
11     int l=p+1,q=r;
12     while(l<=q){
13         while(a[l]<=x&&l<=q) ++l;
14         while(a[q]>x&&l<=q) --q;
15         if(l<=q) swap(a[l],a[q]);
16      }
17      swap(a[p],a[q]);
18      return q;
19 }

   在这三个点中找中间值做为基准点在某些状况下也并不能表明整个序列的中间值,为了能获得一个真正的中间值,咱们在此基础上又提出了进一步求中间值的方法。ui

 绝对中值法

  思想:将一个数组分红每五个元素一组,若最后一组元素不足五个,也做为一组。而后使用一个数组来存储每一个划分中的中间值,获得每一个划分的中间值后,取这个数组的中间值,即为所求的中间值。spa

  获得中间值的代码以下:code

 1 void insertsort(int a[],int p,int q){//插入排序 
 2     int temp;
 3     for(int i=p;i<=q;i++){
 4         if(a[i]<a[i-1]){
 5             temp=a[i];
 6             for(int j=i;j>=0;j--){
 7                 if(j>0&&a[j-1]>temp) a[j]=a[j-1];
 8                 else {
 9                     a[j]=temp;
10                     break;
11                 }
12             }
13         }
14     }
15 }
16 int getmid(int a[],int p,int r){
17     int length=r-p+1;
18     int grouplength=(length%5==0)?(length/5):(length/5+1);//每五个元素一组,获得划分的个数 
19     int *medians=new int[grouplength];//定义存储中间值的数组
20     int midIndex=0;
21     for(int i=0;i<grouplength;i++){
22         if(i==grouplength-1){//最后一组时 ,须要单独处理,由于这组中元素个数小于5个 
23             insertsort(a,p+j*5,r);//调用插入排序 
24             medians[midIndex++]=a[(p+j*5+r)/2];//存入数组 
25         }else {
26             insertsort(a,p+j*5,p+j*5+4);
27             medians[midIndex++]=a[(p+j*5+2)];
28         }
29     } 
30     insertsort(mediams,0,grouplength-1);
31     return medians[grouplength/2];
32 } 

 

 

   这种方法获得中间值的时间复杂度为O(n),可是一般咱们并不使用它,更多的是使用三点中值法。htm

 当序列中元素较少时,使用插入排序

  思想:虽然说插入排序的时间复杂度为O(n2),可是其实是:n(n-1)/2。快速排序的时间复杂度为O(nlogn),其实是:n(logn+1)。通过计算后发现当n<=8时,插入排序所消耗的时间是少于快速排序的。blog

  通过优化后的代码是:排序

  

 1 quicksort(int a[],int l,int r){//快排递归形式 
 2     if(l<r){
 3         if((r-l+1)<=8) insertsort(a,l,r);//调用插入排序
 4         else{
 5             int q=partition(a,l,r);//找到中间数,不必定是中位数 
 6             quicksort(a,l,q-1);
 7             quicksort(a,q+1,r);            
 8         } 
 9     }
10 }

 

 

 上述就是比较经常使用的三种优化方法了。递归

相关文章
相关标签/搜索