快速排序的描述
像合并排序一样,快速排序也是基于分治模式的。下面是对一个典型子数组A[p..r]排序的分治过程的三个步骤。
- 分解:数组A[p..r]被划分成两个(可能空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A(q),而且,小于等于A[q+1..r]中的元素。下标q也在这个划分过程中进行计算。
- 解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1, r]排序。
- 合并:因为两个子数组是就地排序的,将它们的合并并不需要操作:这个数组A[p...r]已排序。
快速排序的实现
下面的过程实现快速排序:
QUICKSORT(A, p, r)
if p < r
then q <- PARTITION(A, p, r)
QUICKSORT(A, p, q-1)
QUICKSORT(A, q+1, r)
为排序一个完整的数组A,最初的调用是QUICKSORT(A, 1, length[A])。
int partition(int arg[], int p, int r)
{
int tmp = arg[r];
int i = p - 1;
int j = 0;
for (j = p; j < r; j++)
{
if (arg[j] <= tmp)
{
i = i + 1;
swap(&arg[i], &arg[j]);
}
}
swap(&arg[i + 1], &arg[r]);
return i + 1;
}
数组划分
快速排序算法的关键是PARTITION过程,它对子数组A[p..r]进行就地重排。
PARTITION(A, p, r)
x <- A[r]
i <- p - 1
for j <- p to r - 1
do if A[j] <= x
then i <- i + 1
exchange A[i] <-> A[j]
exchange A[i+1] <-> A[j]
return i+1
C语言实现
void quicksort(int arg[], int p, int r)
{
int q = 0;
if (p >= r)
{
return;
}
else
{
q = partition(arg, p, r);
quicksort(arg, p, q - 1);
quicksort(arg, q + 1, r);
}
}
答:返回的q值根据函数partition()的第八行来计算,如果是“小于等于”tmp,那么就返回r值,如果只是“小于”,那么就放回p值。
if (arg[j] <= tmp)
在调用partition后,左边的子数组和右边的子数组分别被递归排序。QuickSort中的第二次递归调用并不是必须的;可以用迭代控制结构代替它。这种技术称作为尾递归。考虑下面的这个快速排序的版本,它模拟了尾递归:
QUICKSROT'(A, p, r)
while p < r
do Partition and sort left subarray.
q <- PARTITION(A, p, r)
QUICKSORT'(A, p, q - 1)
p <- q + 1