今天和大家一起讨论快速排序,对于包含n个数的输入数组来说,快速排序是一种最坏情况时间复杂度为o(n * n)的排序算法。虽然最坏情况时间复杂度很差,但是快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好;它的期望时间复杂度为o(n lgn),而且o(n lgn)中隐含的常数因子非常小。另外,它还能进行原址排序,甚至在虚存环境中也能很好的工作。
快速排序的描述:
与归并排序一样,快速排序也使用了分治思想,下面是对一个典型的子数组A[p...r]进行快速排序的三步分治过程:
分解:数组A[p...r]被划分为两个(可能为空)子数组A[p...q - 1]和A[q + 1...r],使得A[p...q - 1]中的每一个元素都小于或等于A[q],而A[q]也小于等于A[q + 1...r]中的每一个元素。其中计算下标q也是划分过程的一部分。
解决:通过递归调用快速排序,对子数组A[p...q - 1]和A[q + 1...r]进行排序。
下面则分别实现quicksort.h和quicksort.c
#ifndef _QUICKSORT_H_
#define _QUICKSORT_H_
#define N 10
//接口声明
void Quicksort(int *data,int p,int r);
int Partition(int *data,int p,int r);
void print_array(int *data,int n);
#endif
对于接口的实现:
#include <stdio.h>
#include <stdlib.h>
#include "quicksort.h"
static void swap(int *a,int *b)
{
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
}
void Quicksort(int *data,int p,int r)
{
int q = 0;
if(p < r){
q = Partition(data,p,r);
Quicksort(data,p,q - 1);
Quicksort(data,q + 1,r);
}
}
int Partition(int *data,int p,int r)
{
int i = p - 1;
int x = data[r];
int j = 0;
for(j = p;j <= r - 1;++j){
if(data[j] < x){
i = i + 1;
swap(&data[i],&data[j]);
}
}
swap(&data[i + 1],&data[r]);
return i + 1;
}
void print_array(int *data,int n)
{
int i = 0;
for(i = 0;i < n;++i){
printf("%5d",data[i]);
}
printf("\n");
}
主程序:
#include <stdio.h>
#include <stdlib.h>
#include "quicksort.h"
int main(int argc ,char **argv)
{
int data[N];
int i = 0;
srand(time(0));
for(i = 0;i < N;++i){
data[i] = rand() % 100;
}
printf("排序前:\n");
print_array(data,N);
Quicksort(data,0,N - 1);
printf("排序后:\n");
print_array(data,N);
return 0;
}
程序执行结果:
快速排序的性能分析:
快速排序的运行时间依赖于划分是否平衡,而平衡与否又依赖于用于划分的元素。如果划分是平衡的,那么快速排序算法性能与归并排序一样。如果划分是不平衡的,那么快速排序的性能就接近于插入排序了。
最坏情况划分:当划分产生的两个子问题分别包含了n - 1个元素和0个元素时,快速排序的最坏情况发生了。不妨假设算法的每一次递归调用都出现了这种不平衡划分。划分操作的时间复杂度是o(n)。由于对一个大小为0的数组进行递归调用会直接返回,因此T(0) = O(1),于是算法的运行时间的递归式可以表示为:
T(n)= T(n - 1)+T(0)+ o(n)= T(n - 1)+o(n)
利用代入法可以直接得到递归式T(n)= o(n * n)
最好情况分析:在可能的最平衡的划分中,Partition得到的两个子问题的规模都不大于n / 2,这是因为其中一个子问题的规模为[n / 2],则另一个子问题的规模为[n / 2] - 1。在这种情况下,排序的性能非常好,此时,算法运行时间的递归式为;
T(n) = 2T(n / 2)+ o(n)
根据定理,上述递归式的解为T(n) = o(n lgn)。