快速排序的是个递归的排序,其核心在划分算法上。
自己随手写的一个快速排序,果然和优化的快速排序差了好远。文后悔分别给出我写的三个进化版的划分函数。
另外,优化排序的一个手段是,把快排和直接插入排序结合起来。因为直接插入排序在序列基本有序的情况下速度非常快!
至于利用快排把数据排序到什么程度再用直接插入排序,珠玑的习题做了实验。有一个折中的值。
下面贴下三个逐步优化的划分算法
// 原始版信手写的快排
int partition( int arr[], int low, int high )
{
int left = low;
int right = high;
int curr = left;
//int curr = rand()
while ( left<right )
{
while( curr<right )
{
if ( arr[curr]>arr[right] )
{
swap( arr[curr], arr[right] );
curr = right;
break;
}
--right;
}
while( left<curr )
{
if ( arr[curr]<arr[left] )
{
swap( arr[curr], arr[left] );
curr = left;
break;
}
++left;
}
}
return curr;
}
// 1:优化了当面对有序序列时,时间复杂度也为n*log(n) 通过随机选择分支实现
// 2:去掉了没有必要的对t值的来回交换,只需要最后的时候放到目标位置上就可以了。
int partition_v2( int arr[], int low, int high )
{
int left = low;
int right = high;
int rand_pos = rand() % (high - low+1) + low;
swap( arr[low],arr[rand_pos] );
int t = arr[low];
int curr = low;
while ( left<right )
{
while( curr<right )
{
if ( t>arr[right] )
{
arr[curr] = arr[right];
curr = right;
break;
}
--right;
}
while( left<curr )
{
if ( t<arr[left] )
{
arr[curr] = arr[left];
curr = left;
break;
}
++left;
}
}
return curr;
}
// 1:优化了curr变量。抓住了快排的本质!
// 2:其实三个参数可以优化为2个参数!
int partition_v3( int arr[], int low, int high )
{
int left = low;
int right = high;
int rand_pos = rand() % (high - low+1) + low;
swap( arr[low],arr[rand_pos] );
int t = arr[low];
while ( left<right )
{
while( t>arr[right] )
{
--right;
}
while( t<arr[left] )
{
++left;
}
}
swap( arr[low], arr[right] );
return right;
}
// 快排算法 high = len-1
void qsort_rec( int arr[], int low, int high )
{
if ( low>=high )
return;
int p = partition( arr, low, high );
int p = partition_v2( arr, low, high );
int p = partition_v3( arr, low, high );
qsort_rec( arr, low, p-1 );
qsort_rec( arr, p+1, high );
}