快速排序:
简化的中值排序;
我们来看看什么是中值排序:
#1对于给定的一个无序数组,我们找到它的中值,并将小于中值的数排到前面,大于中值的数排在后面。O(n) //假设找中值已经找到
#2分治:分别中值排序两边的数组;O(logN)
难点:如何选择中值
方案1:多次的partition,一次partition(随机选择一个位置作为基准),partition之后返回基准最后的位置,如果在中间偏左则往右边找基准,反之往左边找基准
经过多次partition可以找到中值(次数k=1~N), selectK O(KN) ---- O(N^2)
//优化
方案2:BFPRT,将原数组分为4个一组,n/4组,4个元素只需要5次即可排序,第三个元素作为基准,将n/4个基准数组的中值作为选择的中值(近似),
由于这个中值针对原数组来说:起码有3/8小于这个中值,起码有2/8大于等于这个中值;**
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12
3,7,10,12
10
那么每次选择的中值都相对靠近真正中值,算法趋近O(n.logN)
快速排序:
每次选择中值随便选一些策略(例如选第一个值,选中间按个,随机选择) 事实证明随机选择效果就比较好了,(且速度快于中值排序(不用真的中值))
#1对于给定的一个无序数组,随机选择基准,并将小于基准的数排到前面,大于基准的数排在后面。O(n) //假设找中值已经找到
由于随机选择基准,不知道最后基准在的位置,因此作如下操作:
1.1 将基准值与最后一个值交换 O(1)
1.2 遍历数组 只要遇到一个比基准小(或等)的数,就往对应位置交换(第一个比基准小的值放到第一个位置,第k个交换到第k个位置) O(n)
1.3 将基准值放到正确的位置(设有M个数比基准小,那么放到第M+1)的位置
1.4返回基准位置
#2分治:分别中值排序两边的数组;O(logN)
2.1如果小于2个元素,排好
2.2否则执行#1,得到基准
2.3快排基准左边
2.4快排基准右边
讨论:
A,时间复杂度:
最好 平均 最坏
O(NlogN) O(NlogN) O(N^2)
最坏情况是:每次partition都选择最大/最小值,一次partition只能缩小一个规模,和线性排序一致。partition要调用N-1次,每次O(N), O(N^2)
B,稳定性: 不稳定排序
在partition过程中,我们依照数组原顺着将小于基准的值依次交换到前面,但是在之前我们将基准值移动到了最后,那么交换就是不稳定的:
例如:我们选择5(1)作为基准
9 ,7 , 8, 5(1), 5(2), 1, 2 ,3 原数组
9 ,7 , 8, 3, 5(2), 1, 2 ,5(1), 交换基准到右边
3 , 7 , 8, 9 , 5(2), 1, 2 ,5(1), 将小于基准的逐个交换到左边
3 , 5(2), 8, 9 , 7 , 1, 2 ,5(1),
3 , 5(2), 1, 9 , 7 , 8, 2 ,5(1),
3 , 5(2), 1, 2 , 7 , 8, 9 ,5(1),
3 , 5(2), 1, 2 , 5(1), 8, 9 ,7 注意交换最后两个5的相对位置发生了变化
只是一个例子,只要基准左右有与基准一样的值都会照成顺序不一致。
快速排序int版本
//随机选择基准(一种策略而已)
int choosePIbyRand(int l,int r){
srand((unsigned)time( NULL));
int pi=rand()%(r-l+1)+l;
return pi;
}
//#改进版qsort
void myswap(int *a,int *b){
int tmp =*a;
*a=*b;
*b=tmp;
}
int partition(int array[],int left,int right){
//随机选择基准(一种策略而已)
int pivot = choosePIbyRand(left,right);
//将基准值转移到右侧,等确定基准的真正位置,再移回去
myswap(&array[pivot],&array[right]);
//凡是比基准小的元素,都移动到左边(第k个比基准小的元素,将会交换到第k个位置)
int store=left;
for(int i=left;i<right;i++){
if(array[i]<=array[right]){
myswap(&array[i],&array[store]);
store++;
}
}
//将基准移动到所有比他小元素的右边一个位置
myswap(&array[right],&array[store]);
return store;
}
void quickSortPro(int array[],int left, int right)
{
if(right>left){
int pi = partition(array,left,right); //选择基准坐标,且保证基准左边小于基准值,基准右边大于基准值
quickSortPro(array,left,pi-1); //分治
quickSortPro(array,pi+1,right);
}
}
void myqs(int array[],int n){
quickSortPro(array,0,n-1);
}
快速排序通用版本,可以排序多种数据,包括结构体某字段:
//##############################################################################
//##############################################################################
//##############################################################################
//扩展版本,可以比较对象里面的字段
void xmyswap(char *a,char *b,int width); //通用交换函数
int compare_int(const void* a,const void *b); //比较函数-int
int compare_char(const void* a,const void *b); //比较函数-char
int xpartition(void* array,int left,int right,size_t size,int(* compareFunc)(const void*,const void *)); //划分
void xquickSortPro(void * array,int left, int right,size_t size,int(* compareFunc)(const void*,const void *)); //通用快排
void xmyqs(void * array,int n,size_t size,int(* compareFunc)(const void*,const void *));
//######################################################################################
//1.1 交换函数
void xmyswap(char *a,char *b,int width){
char tmp;
while(width--){
tmp=*a;
*a++=*b;
*b++=tmp;
}
}
//######################################################################################
//1.2比较函数
//compare(a,b) a>b >0 a<b <0 a==b =0 只看结果是否大于0
//int
int compare_int(const void* a,const void *b){
return *(int *)a-*(int *)b;
}
//char
int compare_char(const void* a,const void *b){
return *(char *)a-*(char *)b;
}
//结构体
struct student{
int id;
char *name;
double data;
};
//
int compare_st_id(const void* a,const void *b){
return (*(student *)a).id - (*(student *)b).id;
}
int compare_st_data(const void* a,const void *b){
return (*(student *)a).data > (*(student *)b).data ? 1:-1;
}
int compare_st_name(const void* a,const void *b){
return strcmp((*(student *)a).name , (*(student *)b).name);
}
//#################################################################################################
//1.3划分
int xpartition(void* array,int left,int right,size_t size,int(* compareFunc)(const void*,const void *)){
int pi = choosePIbyRand(left,right);
char *a=(char*)array+pi*size;
char *b=(char*)array+right*size;
xmyswap(a,b,size);
int store=left;
for(int i=left;i<right;i++){
char *c=(char*)array+i*size;
char *d=(char*)array+right*size;
if(compareFunc(c,d) <= 0){
a=(char*)array+i*size;
b=(char*)array+store*size;
xmyswap(a,b,size);
store++;
}
}
a=(char*)array+right*size;
b=(char*)array+store*size;
xmyswap(a,b,size);
return store;
}
//#################################################################################################
void xquickSortPro(void * array,int left, int right,size_t size,int(* compareFunc)(const void*,const void *)){
if(right>left){
int pi=xpartition(array,left,right,size,compareFunc);
xquickSortPro(array,left,pi-1,size,compareFunc);
xquickSortPro(array,pi+1,right,size,compareFunc);
}
}
//#################################################################################################
void xmyqs(void * array,int n,size_t size,int(* compareFunc)(const void*,const void *)){
xquickSortPro(array,0,n-1,size,compareFunc);
}
//#################################################################################################
//打印函数
void printArray(int array[],const int n){
for(int i=0;i<n;i++)
{
printf("%d ",array[i]);
}
printf(".\n");
}
void printCharArray(char array[],const int n){
for(int i=0;i<n;i++)
{
printf("%c ",array[i]);
}
printf(".\n");
}
void printStudent(student array[],const int n){
for(int i=0;i<n;i++)
{
printf("%d ",array[i].id);
printf("%s ",array[i].name);
printf("%f",array[i].data);
printf(".\n");
}
printf(".\n");
}
int main(int argc, char* argv[])
{
int b1[]={13,12,11,10,9,2,2,2,8,7,6,5,4,3,1};
int b2[]={13,12,11,10,9,2,2,2,8,7,6,5,4,3,1};
int b3[]={3,2,1,5};
int b5[]={3,2,1,5};
//function->quickSort(b1,0,14);//算法写错了
//function->printArray(b1,15);
quickSortPro(b2,0,14);//算法修改
printArray(b2,15);
//
//通用版测试:
//int
int b4[]={13,12,11,10,9,2,2,2,8,7,6,5,4,3,1};
xmyqs(b4,15,sizeof(int),compare_int);
printArray(b4,15);
//char
char c1[]={'e','a','f','g','p','b','c','g','o','u','x'};
char c2[]={'c','o','e','a','f','g','p','b','g','u','x'};
xmyqs(c1,11,sizeof(char),compare_char);
printCharArray(c1,11);
xmyqs(c2,11,sizeof(char),compare_char);
printCharArray(c2,11);
//结构体
student s0[7]={{1,"terry",90.0},{7,"marry",80.0},{2,"tom",7.0},{5,"andy",9.0},{6,"tusiki",8.5},{3,"xx",70.0},{4,"yy",55.0}};
student s1[7]={{1,"terry",90.0},{7,"marry",80.0},{2,"tom",7.0},{5,"andy",9.0},{6,"tusiki",8.5},{3,"xx",70.0},{4,"yy",55.0}};
student s2[7]={{1,"terry",90.0},{7,"marry",80.0},{2,"tom",7.0},{5,"andy",9.0},{6,"tusiki",8.5},{3,"xx",70.0},{4,"yy",55.0}};
xmyqs(s0,7,sizeof(student),compare_st_id);
xmyqs(s1,7,sizeof(student),compare_st_data);
xmyqs(s2,7,sizeof(student),compare_st_name);
printStudent(s0,7);
printStudent(s1,7);
printStudent(s2,7);
return 0;
}