快速排序通常是排序的最佳选择,因为其平均的运行时间为O(nlgn )。最坏情况下每次划分都产生两个分别包含n-1个元素和一个元素的区域,此时时间复杂度为o(n²)。最佳情况下每次划分都将数组分成两个长度差不多的区域,此时时间复杂度与平均性能差不多。
快速排序的递归形式如下:
void do_quick_sort( int array[], int low, int high ) { if( low < high )
{ int par = partition( array, low, high ); do_quick_sort( array, low, par-1 ); do_quick_sort( array, par+1, high ); } }
快速排序采用分治思想,其中partition函数实现的就是“分”,它将array[low,high]分成两部分,其中前一部分中的元素均小于后一部分中的元素。然后递归调用快速排序对分出来的两部分进行快速排序。
partition函数的代码如下:
int partition( int array[], int low, int high ) { int current = array[low]; while( low < high ) { while( low < high && array[high] >= current )//从后向前寻找第一个小于current的元素 --high;//每次循环时都要确保low<high,否则会出现low>high的情形 array[low] = array[high]; while( low < high && array[low] <= current )//从前向后寻找第一个大于current的元素 ++low; array[high] = array[low]; } array[low] = current; return low; }
该函数可以分为4步理解:
1.从后向前寻找第一个小于current的元素,找到后将它赋值给array[low](array[low]已经由current保存,这也是划分的基准值),
2.然后从前向后寻找第一个大于current的元素,找到后将它赋值给array[high],
3.重复1、2,直至low==high,
4.将current赋值给array[low](或array[high]),这时current前面的值都小于等于它,后面的值都大于等于它,这样array就被分成的两部分
有几个问题需要注意:
1.不论从前向后查找或是从后向前查找都要判断low<high,否则,在循环过程中会出现high<low的情形
2.由于是递归算法,所以程序中必须要有递归结束的条件,即:low>high,所以如果low<high,则继续执行,否则,退出。
快速排序还有几个优化版本,随机化快排就是其中之一,这样是期望对数组的划分更加对称,避免最坏情况的发生。在随机化版本中,只需对partition函数进行修改就可以了。
int randomized_partition( int array[], int low, int high ) { if( low < high ) { srand( (unsigned)time(0) );//为rand函数指定随机数种子 int index = rand()%(high-low)+low;//产生[low,high)区间的随机数 int temp = array[index]; array[index] = array[low]; array[low] = temp; } return partition( array, low, high ); }
通过随机指定[low,high]中的元素作为主元,可以获得较好的平均情况性能。很多人认为,快排的随机化版本是对足够大的输入的理想选择。
快速排序的递归实现
最新推荐文章于 2023-09-14 20:49:02 发布