快速排序算法是对冒泡排序算法的改进,它通常是实际排序应用中最好的一个选择。它的平均性能较好,虽然最坏情况下的时间复杂度为
Θ(n2)
比较高,但它的期望时间复杂度为
Θ(nlogn)
。还有它能够进行原址排序,原址排序是指:在排序算法中对数组中元素进行重排,任何时候数组中仅有常数个元素需要存储在数组之外。插入排序和堆排序也属于原址排序。
快速排序算法的基本思想是:选取一个基准元素,通过一次排序将带排序的记录分成独立的两部分,使得左边部分记录的元素均小于或等于基准元素,右边部分记录的元素均大于或等于基准元素,再分别对这两部分记录进行快速排序,最终达到整个序列有序。
可以看出快速排序算法使用的是分治思想,下面对子数组A[low..high] ( A[low..high]表示数组A的一个子数组,包含元素A[low],A[low+1],…,A[high-1],A[high] )的快速排序的分治过程进行描述如下:
(1)选取一个基准元素设为key,将A[low..high]划分为A[low..point-1]和A[point+1..high],使得A[low..point-1]中的每一个元素均小于等于key,A[point+1..high]中的每一个元素均大于等于key,在此划分过程中同时要计算出下标point即划分过后基准元素key所在位置,再将key存放在元素A[point]上。
(2)通过递归调用快速排序,对划分的子数组A[low..point-1]和A[point+1..high]进行排序。
因为子数组都是进行原址排序,所以不需要进行合并,最后便可直接得到有序的数组A[low..high]。
对文字描述还没有什么感觉的话,可以接着看代码。
// 对子数组A[low..high]进行快速排序
void QuickSort(int A[], int low, int high)
{
int point;
if( low < high ) // 至少要有两个元素
{
point = Partition(A, low, high); // 划分并得到下标point
QuickSort(A, low, point-1); // 对左边部分进行快速排序
QuickSort(A, point+1, high); // 对右边部分进行快速排序
}
}
算法的关键部分是划分过程,即上面代码中的Partition函数过程,它实现了对子数组A[low..high]的原址重排。
// Partition函数实现
int Partition(int A[], int i, int j)
{
int key = A[i]; // 选取子数组的第一个元素为基准元素
while (i < j)
{
while (i < j && A[j] >= key) // 找到比基准元素值小的元素
{
--j;
}
if (i < j) // 将比基准元素值小的元素交换到低端
{
A[i++] = A[j];
}
while (i < j && A[i] <= key) // 找到比基准元素值大的元素
{
++i;
}
if (i < j) // 将比基准元素值大的元素交换到高端
{
A[j--] = A[i];
}
}
A[i] = key;
return i; // 返回基准元素所在位置
}
为了更好的理解代码,这里再用示例加以说明。下图纯粹手画,大家凑合着看啊。
假设对数组A[10]={80,16,100,35,85,20,12,90,110,5}进行快速排序,划分过程即执行Partition(A, 0, 9)的过程如下所示:
具体的完整代码如下:
#include <stdio.h>
void swap(int A[], int low, int high)
{
int temp;
temp = A[low];
A[low] = A[high];
A[high] = temp;
}
// Partition函数实现
int Partition(int A[], int i, int j)
{
int key = A[i]; // 选取子数组的第一个元素为基准元素
while (i < j)
{
while (i < j && A[j] >= key) // 找到比基准元素值小的元素
{
--j;
}
if (i < j) // 将比基准元素值小的元素交换到低端
{
A[i++] = A[j];
}
while (i < j && A[i] <= key) // 找到比基准元素值大的元素
{
++i;
}
if (i < j) // 将比基准元素值大的元素交换到高端
{
A[j--] = A[i];
}
}
A[i] = key;
return i; // 返回基准元素所在位置
}
// 对子数组A[low..high]进行快速排序
void QuickSort(int A[], int low, int high)
{
int point;
if( low < high ) // 至少要有两个元素
{
point = Partition(A, low, high); // 划分并得到下标point
QuickSort(A, low, point-1); // 对左边部分进行快速排序
QuickSort(A, point+1, high); // 对右边部分进行快速排序
}
}
int main()
{
int a[] = { 80,16,100,35,85,20,12,90,110,5 };
int len = sizeof(a) / sizeof(int);
QuickSort(a, 0, len - 1);
printf("排序后的结果是:");
for (int i = 0; i < len; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}