快排细则

19 篇文章 0 订阅
3 篇文章 0 订阅

来源于:http://wenku.baidu.com/view/3567c018964bcf84b9d57b2f.html

                                         
关于快排,其原理及实现网上可以找到很多,我给出的那些动画视频链接里面也有形象的演示,可以上网搜到很多,这里主要讲的是怎样调用系统提供的快排库函数:qsort,它包含在<stdlib.h>头文件里,函数一共四个参数,在函数头部加上#include<stdlib.h>,就可以直接调用,并且无需声明。一个典型的qsort的写法如下:
qsort(s,n,sizeof(s[0]),cmp);
  其中第一个参数s是参与排序的数组名(或者也可以理解成开始排序的地址,因为可以写成&s[i]这样的表达式,这个问题下面有说明);第二个参数n是参与排序的元素个数; 第三个参数是单个元素的大小,必须sizeof(s[0])这样的表达式,下面也有说明;第四个参数cmp其实是个函数名字,它是为指导qsort如何进行排序而专门写的一个函数,我们称之为比较函数,其目的是为了告诉qsort要以什么样的方式进行排序(降序?升序?或者按照某个关键字进行排序等)(注:写成cmp只是一个名字,可以随便怎么写),cmp这个函数有形参,和返回值(int型),但是在调用时却不需要给它传递实参进去,直接调用其名字即可,这个函数是专门为qsort开发的一种函数形式,这个函数的典型定义是:
intcmp(const void *a,const void*b);(红色字体是其固定模式,必须这样写,黑色的则是自己随便起的名字)(其函数体详见后面),并且规定这个函数只能返回int型值。

              关于快排的一些小问题
  1.快排的复杂度,当元素个数比较少时(10^2的数量级左右),快排的速度跟冒泡相比并没有快很多,还有如果要排序的元素大部分都已经是排好顺序了时,快排效率会下降,但是其最坏情况是N^2(当元素全部是已经排好的顺序时),一般情况(也即平均效率)是N*Log2(N),最好情况是N(当元素全部是逆序时),快排的特点是元素越乱排序速度越快,所以可以看出,虽然元素少时使用快排并没有很大优势,但是在快排的最坏情况跟冒泡、选择排序(冒泡、选择排序其复杂度不受元素顺序影响,永远为N^2)一样,所以快排永远是最快的。
  2.快排是不稳定的,这里的稳定性是指对于相同元素的处理上,快排会打乱相同元素的先后顺序(原因就在于快排排序原理,其排序过程是不断把元素分组打乱进行的),当然如果单纯排序一列数字是没什么区别的,假设我们有这样一列数字3,3,3,但是三个3是有区别的,我们标记为3a,3b,3c,快排后的结果不一定就是3a,3b,3c这样的排列,所以在某些特定场合我们要用结构体来使其稳定(No.5的例子就是说明这个问题的)
  3.快排的比较函数cmp的两个参数必须都是constvoid *的,这个要特别注意,写a和b只是个人喜好,写成cmp也只是个人喜好.
  4.快排qsort的第三个参数,sizeof,推荐是使用sizeof(s[0])这样,特别是对结构体,往往自己定义2*sizeof(int)这样的会出问题,用sizeof(s[0)既方便又保险
  5.如果要对数组进行部分排序,比如对一个s[n]的数组,要对其从s[i]开始的m个元素进行排序,只需要在第一个和第二个参数上进行一些修改:qsort(&s[i],m,sizeof(s[i]),cmp);

              注:以下所有程序都已经在visual studio2008上编译通过
No.1最常见的,对int数组排序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int s[10000],n,i;
intcmp(const void *a, const void *b)
{
return(*(int *)a-*(int *)b);/*这里的(int*)a定义了一个指向int型的指针,注意int *两边的括号不能少,然后(int *)a前面加上*就表示取其指向的值。这里返回的是*(int *)a-*(int*)b,两个数相减的顺序跟函数形参顺序一样这样就会将数组按升序排序,反之如果是return(*(int *)b-*(int*)a),就会将数组按降序排列*/
}
voidmain()
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&s[i]);
qsort(s,n,sizeof(s[0]),cmp);
for(i=0;i<n;i++)
printf("%d\n",s[i]);
}

              No.2对double型数组排序

              原理和int相似,不过这里做个注释,本来是要判断如果a==b返回0的,但是严格来说,两个double数是不可能相等的,只能说fabs(a-b)<1e-20之类的这样来判断,所以这里只返回了1和-1
#include<stdio.h>
#include<stdlib.h>
double s[1000];
inti,n;
int cmp(const void * a, const void *b)
{
return((*(double*)a-*(double*)b>0)?1:-1);/*注意这里不能像上面对int型数组排序时那样直接返回*(double*)a-*(double*)b,因为这个cmp函数的返回值已经规定了是int型,而*(double*)a-*(double*)b是double型,这里是对这个double型数组进行了升序排列,如果return((*(double*)b-*(double*)a>0)?1:-1)或者return((*(double*)a-*(double*)b>0)?-1:1)则对数组进行降序排列*/
}
void main()
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%lf",&s[i]);
qsort(s,n,sizeof(s[0]),cmp);
for(i=0;i<n;i++)
printf("%lf\n",s[i]);
}

              No.3对一个字符数组排序

              原理同int
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char s[10000],i,n;
int cmp(const void *a,const void*b)
{
return(*(char *)a-*(char*)b);//这里直接把字符的ASCII码相减来比较字符的先后顺序
}
intmain()
{
scanf("%s",s);
n=strlen(s);
qsort(s,n,sizeof(s[0]),cmp);
printf("%s",s);
}

              No.4对结构体排序
#include<stdio.h>
#include<stdlib.h>
struct node
{
double date;
int flag;
}s[100];
int i,n;
int cmp(const void *a,const void*b)
{
return(((struct node *)a)->date>((struct node*)b)->date?1:-1);/*注意,这里的struct node*跟前面的int*,double*原理一样,都是一种指针类型,这里是自己定义的一个指向结构体的指针类型,故写法为struct 结构体名称*,这里date是double型数据,故不可能有相等情况出现,只需返回1和-1即可*/
}
intmain()
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
s[i].flag=i+1;
scanf("%lf",&s[i].date);
}
qsort(s,n,sizeof(s[0]),cmp);
for(i=0;i<n;i++)
printf("%d %lf\n",s[i].flag,s[i].date);
}

              No.5对结构体排序的补充

              由于快排具有不稳定性,故需要加入flag标志记录先后顺序,来使其稳定(即data值相等的情况下按flag的值大小排序)
#include<stdio.h>
#include<stdlib.h>
struct node
{
double date;
int flag;
} s[100];
int i,n;
int cmp(const void *a,const void*b)
{
if(((struct node *)a)->date !=( (struct node*)b)->date)
return(((struct node *)a)->date>((struct node*)b)->date?1:-1);
else
return(((struct node *)a)->flag - ((structnode *)b)->flag);
}
intmain()
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
s[i].flag=i+1;//flag记录了输入的先后顺序
scanf("%lf",&s[i].date);
}
qsort(s,n,sizeof(s[0]),cmp);
for(i=0;i<n;i++)
printf("%d %lf\n",s[i].flag,s[i].date);
}

              No.6对字符串数组的排序(char s[][]型)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char s[100][100];
int i,n;
int cmp(const void *a,constvoid*b)
{
return(strcmp((char*)a,(char*)b));/*这里调用了strcmp比较函数,这个函数根据字典序对字符串进行比较,按字符串的先后顺序依次返回1或0或-1*/
}
voidmain()
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%s",s[i]);
qsort(s,n,sizeof(s[0]),cmp);
for(i=0;i<n;i++)
printf("%s\n",s[i]);
}
No.7对指针数组排序(char *s[]型)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *s[100];//定义了一个指针数组,亦可称为指针的指针
int i,n;
intcmp(const void *a,const void*b)
{
return(strcmp(*(char**)a,*(char**)b));//注意这里使用char**表示指针的指针
}
intmain()
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
s[i]=(char*)malloc(sizeof(char*));
scanf("%s",s[i]);
}
qsort(s,n,sizeof(s[0]),cmp);
for(i=0;i<n;i++)
printf("%s\n",s[i]);
}

自己增加的:

关于对二维数组全部元素的排序:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int compare(const void*a,const void*b)
{
return *(int*)a-*(int*)b;
}
int main()
{
int i,j;
int array[5][5];
//随机赋值
for(i=0;i<5;i++)
   for(j=0;j<5;j++)
    array[i][j]=rand()%100;
puts("排序前:");
for(i=0;i<5;i++)
{
   for(j=0;j<5;j++)
    printf("%d\t",array[i][j]);
   puts("");
}  
//调用快速排序
qsort(array,25,sizeof(int),compare);
puts("排序后:");
for(i=0;i<5;i++)
{
   for(j=0;j<5;j++)
    printf("%d\t",array[i][j]);
   puts("");
}
return 0;
}

关于对二维数组每行元素的排序:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int compare(const void*a,const void*b)
{
return *(int*)a-*(int*)b;
}
int main()
{
int i,j;
int array[5][5];
//随机赋值
for(i=0;i<5;i++)
   for(j=0;j<5;j++)
    array[i][j]=rand()%100;
puts("排序前:");
for(i=0;i<5;i++)
{
   for(j=0;j<5;j++)
    printf("%d\t",array[i][j]);
   puts("");
}  
//调用快速排序
for(i=0;i<5;i++)
   qsort(array[i],5,sizeof(int),compare);
puts("排序后:");
for(i=0;i<5;i++)
{
   for(j=0;j<5;j++)
    printf("%d\t",array[i][j]);
   puts("");
}
return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值