1. 快速排序算法
快速排序算法是程序员要知道的经典算法之一。快速排序算法,平均时间复杂度为,最坏的时间复杂度为,但是这种概率比较小,可能说这个算法时间复杂度跟归并算法差不多,但为什么还受到这么多人青睐呢,一个重要的原因是它不需要额外的空间进行副本拷贝,是一种原地(in-place)排序算法。从上述大家也可能推算出,快速排序算法的时间复杂度并不是特别统一。确实,这是因为基准“pivot”选择的不同而导致的。那具体什么是pivot呢?又怎么选择pivot呢?
1.1 算法描述:
快速排序算法,采用了分治法的思想。步骤如下:
快速排序处理:
- 第一步(分):在输入数列中,选择一个元素作为pivot,元素值记为x,使得整个数列由两部分A和B组成,满足A = {a | a <= x}且B={b|b>=x};
- 第二步(治):分别对A和B递归快速排序处理。
- 第三步(合):无此步骤,忽略。
算法伪代码如下:
Partition(A, p, q) // A[p, …, q]
x ← A[p] // pivot = A[q]
i ← p
for j ← p+1 to q
do if A[j] <= x
than i ← i+1
swap(A[i+1], A[j])
swap( A[p], A[i])
return i;
quicksort(A,p, q)
if p < q
than r ← Partition(A, p, q)
quicksort(A,p, r-1)
quicksort(A,r+1, q)
Init call :quicksort(A, 1, n)
1.2 算法执行过程
1.3 时间复杂度
此处可以发现,当对于特定数列输入A时,若每次运算r是一个固定值时,快速排序算法的运行时间是一个确定的值, 但此时有可能低于平均时间复杂度,也有可能高于。如果对于相同数列的输入,要使得算法的时间复杂度不取决于数列输入顺序的话,就必须要求基准pivot必须取得足够的聪明,即随机选取pivot。
这样即使对于相同的输入,运行10000000000次排序,每一次的pivot都有可能不相同,而且最终算法复杂度的期望值趋近于。
1.3 C语言实现
static int partition (int array[], int start, int end)
{
int pivot = array[start];
int j=end, i = start;
while (i < j) {
while ((i < j) && (pivot <= array[j])) {
j--;
}
array[i] = array[j];
while ((i < j) && (pivot >= array[i])) {
i++;
}
array[j] = array[i];
}
array[i] = pivot;
return i;
}
void quicksort (int array[], int start, int end)
{
int r;
if (end > start) {
r = partition(array, start, end);
quicksort(array, start, r - 1);
quicksort(array, r + 1, end);
}
}