快速排序 qsort()函数

来源:互联网 发布:淘宝html代码 编辑:程序博客网 时间:2024/05/22 09:04

C语言标准库函数qsort那点小事

qsort包含在<stdlib.h>头文件中,此函数根据你给的比较条件进行快速排序,通过指针移动实现排序。排序之后的结果仍然放在原数组中。使用qsort函数必须自己写一个比较函数。

函数原型:

void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );

函数一共四个参数,没返回值。一个典型的qsort的写法如下:

void qsort(s,n,sizeof(s[0]),cmp);

其中第一个参数是参与排序的数组名(或者也可以理解成开始排序的地址,因为可以写&s[i],这个问题下面有说明);第二个参数是参与排序的元素个数; 第三个参数是单个元素的大小(推荐使用sizeof(s[0])这样的表达式,下面也有说明);第四个参数就是很多人觉得非常困惑的比较函数,关于这个函数,还要说的比较麻烦...

下面来讨论cmp这个比较函数(写成cmp是我的个人喜好,你可以随便写成什么,比如qcmp什么的)。典型的cmp的定义是:

int cmp(const void *a,const void *b);

返回值必须是int,两个参数的类型必须都是const void *,那个a,b是我随便写的两个参数。 假设是对int排序的话,如果是升序,那么就是如果a比b大返回一个正值,小则负值,相等返回0,后面有例子来说明对不同的类型如何进行排序。

在函数体内要对a,b进行强制类型转换后才能得到正确的返回值,不同的类型有不同的处理方法。具体情况请参考后面的例子。

**** 关于快排的一些小问题 ****

1、快排是不稳定的,这个不稳定一个表现在其使用的时间是不确定的,最好情况(O(n))和最坏情况(O(n^2))差距太大,我们一般说的O(nlog(n))都是指的是其平均时间。

2、快排是不稳定的,这个不稳定表现在如果相同的比较元素,可能顺序不一样,假设我们有这样一个序列,3,3,3,但是这三个3是有区别的,我们标记为3a,3b,3c,快排后的结果不一定就是3a,3b,3c这样的排列,所以在某些特定场合我们要用结构体来使其稳定(No.6的例子就是说明这个问题的)。

3、快排的比较函数的两个参数必须都是const void *的,这个要特别注意,写a和b只是我的个人喜好,写成cmp也只是我的个人喜好。推荐在cmp里面重新定义两个指针来强制类型转换, 特别是在对结构体进行排序的时候。

4、快排qsort的第三个参数,那个sizeof,推荐是使用sizeof(s[0])这样,特别是对结构体,往往自己定义2*sizeof(int)这样的会出问题,用sizeof(s[0)既方便又保险。

5、如果要对数组进行部分排序,比如对一个s[n]的数组排列其从s[i]开始的m个元素,只需要在第一个和第二个参数上进行一些修改:

void qsort(&s[i],m,sizeof(s[i]),cmp);

*** 标程,举例说明 ***

No.1、手工实现QuickSort:

基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

复制代码
#include<stdio.h>#include<stdlib.h>void QuickSort(int *A,int left,int right){    if(left>=right) return;    int x=A[(left+right)>>1],low=left,high=right;    while(low<high)    {        while(A[low]<x)            low++;        while(A[high]>x)            high--;        if(low<=high)        {            int Temp=A[low];            A[low]=A[high];            A[high]=Temp;            low++;            high--;        }    }    QuickSort(A,left,high);    QuickSort(A,low,right);}int main(){    int length,i,r[10000];    scanf("%d",&length);    for(i=1;i<=length;i++)        scanf("%d",&r[i]);    QuickSort(r,1,length);    for(i=1;i<=length;i++)        printf(" %d",r[i]);    printf("\n");    system("pause");    return 0;}
复制代码

或者:

复制代码
#include<stdio.h>#include<stdlib.h>int QKPass(int r[],int left,int right){    int low,high,x;    x=r[left];//选择基准记录    low=left;    high=right;    while(low<high)    {        while(low<high&&r[high]>=x)//从右到左找到小于x的记录            high--;        if(low<high)        {            r[low]=r[high];//找到后进行替换            low++;        }        while(low<high&&r[low]<x)        {            low++;        }        if(low<high)        {            r[high]=r[low];            high--;        }        r[low]=x;//将基准记录保存在low=high的位置        return low;//返回基准记录的位置    }}int QKSort(int r[],int low,int high){    int pos;    if(low<high)    {        pos=QKPass(r,low,high);        QKSort(r,low,pos-1);        QKSort(r,pos+1,high);    }}int main(){    int length,i,r[10000];    scanf("%d",&length);    for(i=1;i<=length;i++)        scanf("%d",&r[i]);    QKSort(r,1,length);    for(i=1;i<=length;i++)        printf("%-3d",r[i]);    printf("\n");    system("pause");    return 0;}
复制代码

No.2、最常见的,对int数组排序 :

复制代码
#include<stdio.h> #include<stdlib.h>int s[10000],n,i;int cmp(const void *a, const void *b) {      return(*(int *)a-*(int *)b);  //升序      //return(*(int *)b-*(int *)a); //降序 }int main() {      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 ",s[i]);     printf("\n");     system("pause");     return 0; }
复制代码

No.3、对double型数组排序,原理同int:

这里做个注释,本来是因为要判断如果a==b返回0的,但是严格来说,两个double数是不可能相等的,只能说fabs(a-b)<1e-20之类的这样来判断,所以这里只返回了1和-1 

复制代码
#include<stdio.h> #include<stdlib.h>double s[1000]; int i,n;int cmp(const void * a, const void * b) {      return((*(double*)a-*(double*)b>0)?1:-1); }int 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("%.2lf ",s[i]);      printf("\n");     system("pause");        return(0); }
复制代码

No.4、对一个字符数组排序.原理同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); }int main() {      scanf("%s",s);      n=strlen(s);      qsort(s,n,sizeof(s[0]),cmp);          printf("%s",s);      printf("\n");     system("pause");     return 0; }
复制代码

No.5、对结构体排序(一级排序):

很多时候我们都会对结构体排序,比如2010年校赛的那个根据几个参数排序,一般这个时候都在cmp函数里面先强制转换了类型,不要在return里面转换,我也说不清为什么,但是这样程序会更清晰,并且绝对是没错的。 这里同样请注意double返回0的问题:

复制代码
#include<stdio.h> #include<stdlib.h>struct node {      double data;      int no; } s[100];int i,n;int cmp(const void *a,const void *b) {      struct node *aa=(node *)a;      struct node *bb=(node *)b;      return(((aa->data)>(bb->data))?1:-1); }int main() {      scanf("%d",&n);      for(i=0;i<n;i++)      {          s[i].no=i+1;          scanf("%lf",&s[i].data);      }      qsort(s,n,sizeof(s[0]),cmp);          for(i=0;i<n;i++)         printf("%d %lf\n",s[i].no,s[i].data);      system("pause");     return 0; }
复制代码

No.6、对结构体排序(二级排序)。加入no来使其稳定(即data值相等的情况下按原来的顺序排):

复制代码
#include<stdio.h> #include<stdlib.h>struct node {      double data;      int no; } s[100];int i,n;int cmp(const void *a,const void *b) {      struct node *aa=(node *)a;      struct node *bb=(node *)b;      if(aa->data!=bb->data)          return(((aa->data)>(bb->data))?1:-1);      else          return((aa->no)-(bb->no)); }int main() {      scanf("%d",&n);      for(i=0;i<n;i++)      {          s[i].no=i+1;          scanf("%lf",&s[i].data);      }      qsort(s,n,sizeof(s[0]),cmp);     for(i=0;i<n;i++)         printf("%d %lf\n",s[i].no,s[i].data);     printf("\n");     system("pause");     return 0; }
复制代码

如果有字符串的话,就这样写:

复制代码
int cmp(const void *a,const void *b) {      struct node *aa=(node *)a;      struct node *bb=(node *)b;      if(aa->data!=bb->data)          return(((aa->data)>(bb->data))?1:-1);      else          return((aa->no)-(bb->no));     else          return strcmp(aa.str,bb.str);         //return strcmp(aa->str,bb->str);         //按照结构体中字符串str的字典顺序排序}
复制代码

 

No.7、对字符串数组的排序(char s[][]型):

复制代码
#include<stdio.h> #include<string.h> #include<stdlib.h>char s[100][100]; int i,n;int cmp(const void *a,const void *b) {      return(strcmp((char*)a,(char*)b)); }int main() {      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]);      printf("\n");     system("pause");     return 0; }
复制代码

No.8、对字符串数组排序(char *s[]型):

复制代码
#include<stdio.h> #include<string.h> #include<stdlib.h>char *s[100]; int i,n;int cmp(const void *a,const void *b){      return(strcmp(*(char**)a,*(char**)b)); }int main() {      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]);     printf("\n");     system("pause");     return 0; }
复制代码
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2岁半宝宝说什么不听话怎么办? 误把脱毛膏当牙膏用了刷牙怎么办 儿子1岁5个月了不说话怎么办 两岁小儿不会说话和智商低怎么办 宝宝不会说话教他说他不愿意怎么办 25个月宝宝不愿意学说话怎么办 老师说小孩在幼儿园老是说话怎么办 在外留学想领养一个外国小孩怎么办 三岁半的宝宝想去美国上学怎么办 农村新房边的老老祖坟不搬怎么办 倒西太阳晒的房子夏天很热怎么办 客厅壁纸用的浅灰色影视墙怎么办 我喜欢玩手机游戏妈妈很生气怎么办 家里墙上有很多白色的虫子怎么办 3岁半宝宝学数字学不会怎么办 小孩子读一年级拼音读不好要怎么办 4个月的婴儿恶心干呕怎么办 生了小孩后胆汁酸偏高怎么办 9个月宝宝吃盐了怎么办 两个月宝宝母乳拉大便太稀怎么办呀 两个月的宝宝不拉大便怎么办 两个月宝宝五天没拉大便怎么办 4个月宝宝不拉大便怎么办 2个月宝宝3天没拉大便怎么办 宝宝拉不出大便老是憋的哭怎么办 九个月的宝宝不爱吃水果怎么办 顺产侧切伤口发炎化脓有臭味怎么办 一岁宝宝感冒发烧39度怎么办 宝宝二岁半了只吃水果不吃饭怎么办 8个月小孩发烧39度怎么办 咳嗽吃了很多药都不见效果怎么办 生完孩子半个月奶水越来越少怎么办 买到了坏了的水果商家不赔怎么办 小孩奶不够吃又不吃奶粉怎么办 10个月的宝宝便秘很严重怎么办 四岁的宝宝突然不怎么吃饭怎么办 1岁7个月宝宝突然不爱吃饭怎么办 宝宝发烧好了之后不吃辅食怎么办 吃母乳的宝宝不喝奶粉怎么办 奶水不足宝宝又不喝奶粉怎么办 6个月宝宝断奶哭闹不用奶瓶怎么办