快排是平均性能最好的排序算法,但是当面对初始有序序列时,速度将会退化到O(n2)。
有一天我就想怎么能把快排在初始有序时排序速度提高,于是在纸上写下一串有序序列,分析其规律,突然发现,如果选择中间的数作为枢轴,是否就能解决这个问题呢?
说干就干,当天用了一下午的时间,对快排进行了改进。
int PationUp(SqList &L,int low,int high)
{//快排升级版,
int pivot; //枢轴
pivot=(high+low)/2;
L.r[0]=L.r[pivot];
while(low
L.r[0].key)
--high;
L.r[pivot]=L.r[high];
pivot=high;
while(low
![]()

在无序时,两种快排速度相差无几,而当初始有序时,改进后的快排速度达到对无序序列排序时的一半,以一亿个随机数为例,在我的电脑上,快排预计需要半年,而改进后的快排只需11秒。
但是,进一步测试发现,当面对含有大量相等元素的序列时,两种快排都会再次退化回O(n2),于是,我采用 if 来控制循环次数,达到两端交替走的效果,当元素全部相等会在正中间分开,避免了一边先走直接走到另一端的情况。不过可能是比较次数过多,略微牺牲了其他情况下的排序性能。
int Pation2(SqList &L,int low,int high)
{
int pivot;
pivot=(high+low)/2;
L.r[0]=L.r[pivot];
while(low
=L.r[0].key)
--high;
if(L.r[high].key<=L.r[0].key)
{
L.r[pivot]=L.r[high];
pivot=high;
}
if(low
=L.r[0].key)
{
L.r[pivot]=L.r[low];
pivot=low;
}
}
L.r[pivot]=L.r[0];
return pivot;
}
void Qsort2(SqList &L,int low,int high)
{
int j;
if(low
![]()

注:1到10等值,是指,比如生成一个含有一万个数的序列,取值范围为1到10,每个数出现的次数为10000/10=1000次。因为我在测试时发现,代码中判定条件的微小差异会对不是所有数都等值的序列造成非常大的影响。
代码中