基本思想:
通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录比另一部分记录的关键字小,然后对这两部分分别进行快速排序,如此重复直到整个序列有序。
实现代码:
void QSort(int a[], int left, int right)
{
int i,j,k;
k = a[left];
i = left;
j = right;
while(i < j)
{
while(a[j] > k && i < j)
{
j--;
}
if(i < j)
{
a[i] = a[j];
i++;
}
while(i < j && a[i] <= k)
{
i++;
}
if(i < j)
{
a[j] = a[i];
j--;
}
}
a[i] = k;
if(i - 1 > left)
{
QSort(a, left, i - 1);
}
if(i + 1 < right)
{
QSort(a, i + 1, right);
}
}
时间复杂度:
快速排序的一次划分算法从两头交替搜索,直到low和high重合,因此其时间复杂度是O(n);而整个快速排序算法的时间复杂度与划分的趟数有关。
理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n)。
最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。
为改善最坏情况下的时间性能,可采用其他方法选取中间数。通常采用“三者值取中”方法,即比较H->r[low].key、H->r[high].key与H->r[(10w+high)/2].key,取三者中关键字为中值的元素为中间数。
可以证明,快速排序的平均时间复杂度也是O(nlog2n)。因此,该排序方法被认为是目前最好的一种内部排序方法。
从空间性能上看,尽管快速排序只需要一个元素的辅助空间,但快速排序需要一个栈空间来实现递归。最好的情况下,即快速排序的每一趟排序都将元素序列均匀地分割成长度相近的两个子表,所需栈的最大深度为log2(n+1);但最坏的情况下,栈的最大深度为n。这样,快速排序的空间复杂度为O(log2n))。
稳定性:
由于快速排序的比较和交换是跳跃式进行的,因此快速排序是一种不稳定的排序算法。