快速排序(Quicksort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序是一种内部排序方法。也就是说快速排序的排序对象是读入内存的数据。
但是快速排序是一种不稳定的排序方法。简单地说,元素a1, a2的关键字有a1.key=a2.key,则不稳定的排序方法不能保证a1, a2在排序后维持原来的位置先后关系。
快速排序每次将待排序数组分为两个部分,在理想状况下,每一次都将待排序数组划分成等长两个部分,则需要logn次划分。而在最坏情况下,即数组已经有序或大致有序的情况下,每次划分只能减少一个元素,快速排序将不幸退化为冒泡排序,所以快速排序时间复杂度下界为O(nlogn),最坏情况为O(n^2)。在实际应用中,快速排序的平均时间复杂度为O(nlogn)。
参考不少资料算写完两个程序:
程序1
#include<stdio.h>
void QuickSort(int e[],int low,int high){
int i=low,j=high,temp=e[low];
while(i<j){
while(i<j&&e[j]>=temp)
j--;
e[i]=e[j];
while(i<j&&e[i]<=temp)
i++;
e[j]=e[i];
}
e[i]=temp;
if(low<i-1){
QuickSort(e,low,i-1);
}
if(high>i+1){
QuickSort(e,i+1,high);
}
}
void main(){
int array[100],a,len;
char ch;
printf("请输入待排数据(不超过100个),以空格间隔、回车键结束\n");
for(a=0;;a++){
scanf("%d%c",&array[a],&ch);
if(ch==10)
break;
}
printf("排序前:");
len=a+1;//因为数组下表从0开始,所以数组长度为最大下标加1
for(int i=0;i<len;i++)
printf("%d ",array[i]);
QuickSort(array,0,len-1);
printf("\n排序后:");
for(i=0;i<len;i++)
printf("%d ",array[i]);
printf("\n");
}
程序2(参考《数据结构》(C语言版)):
// DataType.h 待排记录的数据类型
#define MAXSIZE 20 //一个用作示例的小顺序的最大长度
typedef int KeyType;//定义关键字类型为整数类型
typedef int InfoType;//定义其他类型
typedef struct{
KeyType key;//关键字项
InfoType otherInfo;//其他数据项
}RedType; //记录类型
typedef struct{
RedType r[MAXSIZE+1];//r[0]闲置或用作哨兵单元
int length;//顺序表的长度
}SqList;//顺序表类型
/**
*QuickSort
*参考《数据结构》(C语言版)
*/
#include<stdio.h>
#include"DataType.h"
int Partition(SqList &L,int low,int high){
//交换顺序表L中子表r[low...high]的记录,枢轴记录到位,并返回其所在位置,
//此时在它之前(后)的记录均不大(小)于它
KeyType pivotKey;
L.r[0]=L.r[low];//用子表的第一个记录作枢轴记录
pivotKey=L.r[low].key;//枢轴记录关键字
while(low<high){//从表的两端交替的向中间扫描
while(low<high&&L.r[high].key>=pivotKey)
--high;
L.r[low]=L.r[high];
while(low<high&&L.r[low].key<=pivotKey)
++low;
L.r[high]=L.r[low];
}
L.r[low]=L.r[0];
return low;//返回枢轴位置
}//Partition
void QSort(SqList &L,int low,int high){
//对顺序表L中的子序列L.[low...high]作快速排序
int pivotLoc;
if(low<high){
pivotLoc=Partition(L,low,high);//将L.[low...high]一分为二
QSort(L,low,pivotLoc-1);
QSort(L,pivotLoc+1,high);
}
}//QSort
void QuickSort(SqList &L){
//对顺序表L作快速排序
QSort(L,1,L.length);
}//QuickSort
void print(SqList &L){
int i;
for(i=1;i<=L.length;i++){
printf("(%d,%d)",L.r[i].key,L.r[i].otherInfo);
}
printf("\n");
}//Print
#define N 8
void main()
{
RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
SqList l;
int i;
for(i=0;i<N;i++)
l.r[i+1]=d[i];
l.length=N;
printf("排序前:\n");
print(l);
QuickSort(l);
printf("排序后:\n");
print(l);
}
快速排序需要一个栈空间来实现递归, 若每一趟排序都将记录序列均匀地分割成长度相接近的两个子序列,则栈的最大深度为[log2n]+1(以2为底)(包括最外层参量进栈),但是,若每趟排序之后,枢轴位置均偏向子序列的一端,则为最坏情况,栈的最大深度为n,如果 在一趟排序之后比较分割所得两部分的长度,且先对长度短的子序列中的记录进行快速排序,则栈的最大深度可降为O(logn)。