1.快速排序算法
快速排序算法由图灵奖获得者Tony Hoare设计出来,被列为20世纪十大算法之一。
快速排序(Quick Sort)的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
假设现在需要对数组{50,10,90,30,70,40,80,60,20}进行排序,则代码如下:
/* 对顺序表L作快速排序 */
void QuickSort(SqList *L)
{
QSort(L, 1, L->length);
}
和归并排序一样,仅是一句代码,接下来看看QSort()函数的实现。
/* 对顺序表L中的子序列L->r[low..high]作快速排序 */
void QSort(SqList *L, int low, int high)
{
int pivot;
if(low<high)
{
pivot = Partition(L, low, high); //将L->r[low..high]一分为二,算出枢轴值pivot
QSort(L, low, pivot-1); //对低子表递归排序
QSort(L, pivot+1, high); //对高子表递归排序
}
}
从这里,就能理解QSort()参数里面的1和L->length的意思了,它们其实就是最小下标值low以及最大下标值high。
这里最核心的代码就是 pivot=Partition(L,low,high)。Partition函数要做的,就是先选取当中的一个关键字,比如选择第一个关键字50,然后想尽办法将它放到一个位置,使得它左边的值都比它小,右边的值比它大,我们将这一的关键字称为枢轴(pivot)。
具体的Partition()函数实现如下:
/* 交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */
/* 此时在它之前(后)的记录均不大(小)于它。 */
int Partition(SqList *L, int low, int high)
{
int pivotkey;
pivotkey=L->r[low]; //用子表的第一个记录作枢轴记录
while(low<high) //从表的两端交替向中间扫描
{
while(low<high && L->r[high]>=pivotkey)
high--;
swap(L,low,high); //将比枢轴记录小的记录交到低端
while(low<high && L->r[low]>=pivotkey)
low++;
swap(L,low,high); //将比枢轴记录大的记录交到高端
}
return low; //返回枢轴所在位置
}
通过上述模拟,Partition()函数,就是将选取的pivotkey不断交换,将比它小的换到它左边,将比它大的换到它右边,同时pivotkey也在交换中不断更改自己的位置,直到完全满足这个要求为止。
2.快速排序算法复杂度分析
在最优的情况下时间复杂度为,最坏情况下时间复杂度为,平均复杂度为。空间复杂度亦为。快速排序是一种不稳定的排序方法