1.选择将第一个元素作为枢纽元。如果输入是随机的,那么这是可以接受的,但如果输入是预排序的或者反排序的,那么这样的枢纽元就产生一个劣质的分割,因为所有的的元素不是被划入S1就是被划入S2。更有甚者,这种情况发生在所有的递归调用中。实际上,如果第一个元素作为枢纽元而且输入是预先排序的,那么快速排序花费的时间将是二次的。
2.三数中值分割法。一组N个数的中值是第[N/2]个最大的数。枢纽元最好的选择是数组的中值。不辛的是,这很难算出,且明显减慢快速排序的速度。这样中值的估计量可以通过随机选取三个元素并用它们的中值作为枢纽元而得到。事实上,随机性没有多大的帮助,因此一般的做法是使用左端、右端和中心位置上的三个元素的中值作为枢纽元。
(后续会加入去随机数作为枢纽元的比较)
下面是用200000个随机数测试的排序耗时:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <windows.h>
#define elementType int
#define Cutoff 3
void Swap(int *a, int *b)
{
int Tmp = *a;
*a = *b;
*b = Tmp;
}
void Qsort1(int A[], int Left, int Right)
{
int i, j, Pivot;
if(Left < Right)
{
Pivot = A[Left];
i = Left;
j = Right - 1;
Swap(&A[Left], &A[Right]);
while(i <= j)
{
while(A[i] < Pivot)
i++;
while(A[j] > Pivot)
j--;
if(i < j)
{
Swap(&A[i], &A[j]);
i++;
j--;
}
else
break;
}
Swap(&A[i], &A[Right]);
Qsort1(A, Left, i - 1);
Qsort1(A, i + 1, Right);
}
}
void quickSort1(int A[], int N)
{
Qsort1(A, 0, N - 1);
}
void insertionSort(int A[], int N)
{
int tmp;
int j, p;
for( p = 1; p < N; p++ )
{
tmp = A[p];
for( j = p; j > 0 && A[j -1] > tmp; j -- )
A[j] = A[j-1];
A[j] = tmp;
}
}
int Median3(int A[], int Left, int Right)
{
int Center = (Left + Right) / 2;
if(A[Left] > A[Center])
Swap(&A[Left], &A[Center]);
if(A[Left] > A[Right])
Swap(&A[Left], &A[Right]);
if(A[Center] > A[Right])
Swap(&A[Center], &A[Right]);
Swap(&A[Center], &A[Right - 1]);
return A[Right - 1];
}
void Qsort2(int A[], int Left, int Right)
{
int i, j, Pivot;
if(Left + Cutoff <= Right)
{
i = Left;
j = Right - 1;
Pivot = Median3(A, Left, Right);
for(; ; )
{
while(A[++i] < Pivot){}
while(A[--j] > Pivot){}
if(i < j)
Swap(&A[i], &A[j]);
else
break;
}
Swap(&A[i], &A[Right - 1]);
Qsort2(A, Left, i - 1);
Qsort2(A, i + 1, Right);
}
else
insertionSort(A + Left, Right - Left + 1);
}
void quickSort2(int A[], int N)
{
Qsort2(A, 0, N - 1);
}
void main()
{
srand(time(0));
int a[200000];
for(int i=0;i<200000;i++)
a[i] = rand();
DWORD dwGTCBegin, dwGTCEnd;
printf("200000个随机数各种排序耗时测试:\n");
dwGTCBegin = GetTickCount();
quickSort1(a, 200000);
dwGTCEnd = GetTickCount();
printf("quickSort1耗时:%5d毫秒\n", dwGTCEnd - dwGTCBegin);
dwGTCBegin = GetTickCount();
quickSort2(a, 200000);
dwGTCEnd = GetTickCount();
printf("quickSort2耗时:%5d毫秒\n", dwGTCEnd - dwGTCBegin);
}
可以看到采用三中值作为枢纽元确实比选用第一个数作为枢纽元运行速度更快。