随机方法避免快排最坏情况,快排中引入插入排序提速分析
1快速排序算法基本思想:
if p<r
then q<- PARTITION(A,p,r) 1//选择位置q,将数组分为两部分
QuickSort(A,p,q-1)
QuickSort(A,q+1,r)
PARTITION(A,p,r)
x<- A[r]
i<- p-1 //定义i为活动指针,向右移动并使A[p…i]<=x
for j<- p to r-1 //定义j为遍历数组A
do if A[j]<= x
then i< i+1 //右移并交换,使满足<=x的元素增加一个
exchange A[i]<->A[j]
exchange A[i+1]<->A[r]
//将A[r]放入i+1位置,使p…i项均小于i+1项,后A[i+2…r]项均大于A[i+1]
return i+1
2改进优化方法:
一、通过采用随机方法,避免最坏情况发生:
在原方法中,选择比较元素为数组最后一个元素。通过随机函数,生成位于p~r之间的随机数为比较项位置(A[random(p,r)]),与原先比较元素(A[r])位置交换,再调用PARTITION方法,伪代码如下:
//该方法能对数组中已经存在部分有序队列的情况进行优化,避免最坏情况发生
Random_PARTITION(A,p,r)
i<- Rand(p,r)
exchange A[i]<->A[r]
return PARTITION(A,p,r)
将Random_PARTITION方法在1处调用即可。
二、当问题规模小于某一k值时,采用插入排序,提高算法效率
修改当r-p<k值时,调用InsertSort方法
修改后方法伪代码为:
QuickSort(A,p,r)
if r-p<k
InsertSort(A,p,r)
else if p<r
then q<- Random_PARTITION (A,p,r)
QuickSort(A,p,q-1)
QuickSort(A,q+1,r)
对k值的讨论取值:
算法复杂度为O(nk+nlog(n/k)),对于每一项的系数有插入排序复杂度为0.5*k*(k-1)*(n/k)=1/2*n*k,可以取nk项系数为c1=1/2。对于采用原快排序的部分,有期望为nlog(n/k),通过递归树证明略,取c2=1,则有下式:
令F(k)= c1*nk+c2*nlog(n/k)=0.5*nk+nlog(n/k)
对F(k)求导,一阶导数=0,二阶导数>0,则有:
k=2/ln2
对k取值约等于3时有最小值,即问题规模<=3时采用插入排序效率更高。
对K值的讨论:
k=3时 0.20s
k=6时0.18s
k=7时0.18s
k=50时0.19s
k=100时0.20s
分析,因为实验环境是core i5 处理器能力较强,对于1000000(1百万)数据时间耗时较短差别较小。在k取7~30左右可有较好范围的实验结果。
实验结果:
实验环境:Ubuntu_x64语言:C++ 数据规模:
实验数据1000000 处理器i5 4核
采用插入排序优化后结果:耗时0.194s k取值为4
直接使用快排结果:耗时0.203S
采用随机方法于原算法比较:
对已经排好序的数组进行排序,对最坏情况进行分析:
问题规模:10000 不采用random 0.138S
采用random方法0.002s
实验结果明显,通过采用随机元素位置,可以避免坏情况带来的特殊值,使算法更接近于时间期望。
原文链接:http://www.cnblogs.com/sunshinewill/archive/2013/03/05/2943642.html
#include <iostream> #include <time.h> #include <stdlib.h> using namespace std; void Insertsort(int list[],int a,int b){ int next,j; if(a>b)return; for(int x=a;x<=b;x++){ next=list[x]; for(j=x-1;j>=a&&next<list[j];j--) list[j+1]=list[j]; list[j+1]=next; } } void quicksort(int list[],int left,int right) { int pivot,i,j; int temp,pos; //k取值为10 if(right-left<10){Insertsort(list,left,right);}else if(left<right) {//注明:在实现过程中,采用i,j从两边向中间遍历的方法,可进一步提高算法的速度 i=left; j=right+1; pos=rand()%(right-left)+left;//采用随机方法 pivot=list[pos]; temp=list[left]; list[left]=list[pos]; list[pos]=temp; //pos =left; do { do i++; while(list[i]<pivot); do j--; while(list[j]>pivot); if(i<j) {temp=list[i]; list[i]=list[j]; list[j]=temp;} }while(i<j); temp=list[left]; list[left]=list[j]; list[j]=temp; quicksort(list,left,j-1); quicksort(list,j+1,right); } else return; } int main() { int i; int n=1000000; int list[1000000]; srand((unsigned)time(NULL)); for(i=0;i<n;i++) list[i]=rand(); quicksort(list,0,n-1); // for(i=0;i<n;i+=20) // cout<<" "<<list[i]; return 0; }