快速排序也是一种分治法的实现。与归并排序的不同是其操作是原地进行的,不需要额外的存储空间。
基本思路:
1、基数的选取,普通快速排序在序列<a1,a2,...,an>中指定a1或an为基数(本例为a1)。
2、记录基数为x。分别定义两个循环L:a2往后的循环;R:an往前的循。两个循环的终止条件是L和R循环到同一个元素时。起始有个空位a1,通过将R循环中比基数x小的数ak放到a1,此时得到空位k,再进行L循环,将比基数x大的数aj放到k的位置,得到空位j。如此反复,当最终L和R指向同一个空位i时。将x放如位置i。则有i之前的元素小于x,i之后的元素大于小。即x已经排好序了。
3、递归排序<a1,...,ai-1>和<ai+1,an>,最终可以得到拍好序的序列。
算法实现
void QuickAdjust(int a[], int left, int right)
{
if (left >= right) //left>right为错误的赋值,=为排序元素个数为1
return;
int x = a[left];
int l = left,r = right; //初始化左右循环的起始值
while(l < r) {
while (l < r && a[r] >= x)
r--;
if(l < r)
a[l++] = a[r];
while(l < r && a[l] < x)
l++;
if(l < r)
a[r--] = a[l];
}
a[l] = x;
QuickAdjust(a, left, l - 1);
QuickAdjust(a, l + 1, right);
}
void QuickSort(int a[], int length)
{
QuickAdjust(a, 0, length - 1); //left和right对应数组的下标
}
时间复杂度分析
最坏情况,当每次选取的基数都为序列中的最大值时,对n位序列的排序递归调用n-1位的排序,有T(n) = T(n-1) + T(1) + O(n),其中T(1)可视为0,即T(n) = T(n-1) + O(n)。可知最坏时间复杂度为O(n^2)。
最优情况,每次选取的基数为序列中的中间值,对n位序列的排序递归调用n/2位的排序。有T(n) = T(n/2) + O(n)。可知最优时间复杂度为O(nlog(n))。
另一个版本的快排(基数随机化)
因为上述快速排序对每次递归选定了特定位置的基数,在一定程度上使得最坏情况的出现概率增大(对排好序的序列时间复杂度最坏),采用基数随机化使时间复杂度接近平均情况。
主要的变化是采用随机函数random在每次递归调用时选取一个随机序号k在1到n之间,令a1与ak交换,再进行快速排序。