快速排序采用“分治法”
首先选取一个“轴值”,假设数据中有k个数小于轴值,那么这k个数放在数组最左边的k个位置上,而不小于k的数放在数组右边的n-k个位置上。
这就实现了数组的一个“分割”。
给定分割中的值不必排序。只要求所有结点都被轴值正确分割。
快速排序再对已经分割的子序列继续进行类似分割。
下图演示了快速排序的执行过程:
源程序:
#include "stdio.h"
template< class Elem >
void swap( Elem list[], int i, int j )
{
Elem e_tmp = list[i];
list[i] = list[j];
list[j] = e_tmp;
}
// 如果以第一个或者最后一个为轴值,那么正序序列或逆序序列
// 的轴值的选择会使所有数分割到一边,影响排序性能
// 而选取随机值开销较大,中间值是不错的选择
int findpivot( int i_start, int i_end )
{
return ( i_start + i_end ) / 2;
}
// 描述:
// 分别从头尾往中间移动,与轴值比较,
// 并且交换左右两边分别比轴值大和比轴值小的数
// 返回值:
// 右边分割序列第一的序号
template< class Elem >
int partition( Elem list[], int i_left, int i_right, Elem e_pivot )
{
do
{
while ( list[++i_left] < e_pivot );
while ( i_right > 0 && list[--i_right] > e_pivot );
swap( list, i_left, i_right );
}while ( i_left < i_right );
// 纠正最后一次不必要的交换
swap( list, i_left, i_right );
// 此时i_left是右边第一个
return i_left;
}
template< class Elem >
int quicksort( Elem list[], int i_start, int i_end )
{
// 递归 结束条件
if ( i_end <= i_start )
return 0;
int i_pivot = findpivot( i_start, i_end );
printf( "i_pivot: %d\n", i_pivot );
// put pivot at end
swap( list, i_pivot, i_end );
// i_start要减1,便于在partition里先自减,再比较
// i_end不需要减1,因为i_end本身已经为pivot
int i_pivot_new = partition( list, i_start - 1, i_end, list[i_end] );
printf( "i_pivot_new: %d\n", i_pivot_new );
// put pivot at the right pivot position
swap( list, i_end, i_pivot_new );
quicksort( list, i_start, i_pivot_new - 1 );
quicksort( list, i_pivot_new + 1, i_end );
return 0;
}
int main()
{
int p_srcarr[] = { 72, 6, 57, 88, 60, 42, 83, 73, 48, 85 };
const int i_len = 10;
printf( "sizeof( p_srcarr ): %d", sizeof( p_srcarr ) );
printf( "%s", "before quicksort\n" );
int i_index = 0;
for( i_index = 0; i_index < i_len; i_index ++ )
{
printf( "%4d", p_srcarr[i_index] );
}
printf( "%s", "\n" );
quicksort( p_srcarr, 0, i_len - 1 );
printf( "%s", "after quicksort\n" );
for( i_index = 0; i_index < i_len; i_index ++ )
{
printf( "%4d", p_srcarr[i_index] );
}
printf( "%s", "\n" );
return 0;
}
快速排序平均时间代价为:
Θ
(nlogn)
参考:
《数据结构与算法分析》