快速排序使用了分治思想。
对典型的子数组A[p..r]进行快速排序的三步分治过程:
分解: 数组A[p..r]被划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得子数组A[p..q-1]的所有元素都不大于A[q],数组A[q+1,r]的元素都大于A[q]中的每个元素。这里需要计算下标q。
解决: 通过递归进行快速排序,对子数组A[p..q-1]和A[q+1,r]都进行快速排序。
合并: 对子数组都是进行原址排序的,因此不需要合并。
//第p到r的元素是要进行快速排序的元素
void quickSort(vector<int> &heap, int p, int r) {
if (p < r) {
int i = partition(heap, p, r);
quickSort(heap, p, i - 1);
quickSort(heap, i + 1, r);
}
}
//以heap[r]为主元。通过函数中的for循环,一直保持p<=k<=i,heap[k]<=x
//i+1<=k<=j-1,heap[k]>x
//j<=k<=r-1,是还未进行比较的元素
//经过所有循环最终结果是 heap[p..i]元素都小于或等于x,heap[i+2..r]元素都大于x.
int partition(vector<int> &heap, int p, int r)
{
int x = heap[r];
int i = p - 1;
int positive = 0;
//这个循环是为了判断子数组heap[p..r]的元素是不是全部相同,如果都相同则返回(p+r)/2
for (int j = p; j <= r; j++) {
if (heap[j] != x)
{
positive = 1;
break;
}
}
if (positive == 0) return (p + r) / 2;
for (int j = p; j < r; j++) {
if (heap[j] <= x) {
i = i + 1;
swap(heap[i], heap[j]);
}
}
swap(heap[i + 1], heap[r]);
return i+1;
}
快速排序的性能
最坏情况的划分。当划分产生的两个子问题分别包含了n-1个元素和0个元素时,最坏的情况发生。 时间复杂度为O(n^2)
平均情况下,时间复杂度为O(n);任何一种常数比例的划分都会产生深度为O(lgn)的递归树,其中每一层的时间代价都是O(n)。因此只要划分是常数比例的,算法的运行时间总是O(nlgn)。
当好和差的划分交替出现时,快速排序的时间复杂度与全是好的划分时是一样的,仍是O(nlgn)。