其他分享
首页 > 其他分享> > C语言qsort排序教程

C语言qsort排序教程

作者:互联网

qsort函数用法简介

前言

在这里先感谢zjh和oyhd两位学长。没有他们两位的悉心指导,我想我肯定不能在短时间学会并熟练使用qsort函数,并在程设期末时用上它。

以下开始正文

先上一个题铺垫一下

大家看完题后应该不难理解,其实就是一个双关键字排序,先排成绩再排姓名的字典序(字典序其实就是根据每个字符的ASCII码值对字符串进行比较

下面直接给例题代码了(这个代码差不多包括qsort排序大部分的内容了)第一遍可以先随便浏览一下,晚点看完下面的再回来看一下

#include<stdio.h>
#include<stdlib.h>//qsort在这个函数库里面
#include<string.h>
struct in{//结构体变量,存储每个人的成绩和名字
    int score;//成绩
    char name[15];//姓名
}a[1005];
int cmp(const void *p,const void *q);{//qsort的比较函数,用于确定比较规则
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){//读入
        scanf("%s %d",a[i].name,&a[i].score);//这个是结构体变量的引用,下面会仔细讲
    }
    qsort(a+1,n,sizeof(a[1]),cmp);//直接qsort排序就行了,是不是很方便hh
    for(int i=1;i<=n;++i){//输出
        printf("%s %d\n",a[i].name,a[i].score);
    }
    /*主函数里面其实相当简单对吧,读入以后直接排序,排完序输出就可以了*/
}
int cmp(const void *p,const void *q){
    struct in c=*(struct in*)p;
    struct in d=*(struct in*)q;//定义结构体c和结构体d来存储p和q中的值,就是套路,记下来用多了就明白了
    if(c.score!=d.score){//先比较成绩,再比较姓名字典序
        return c.score>d.score?-1:1;//
    } else return strcmp(c.name,d.name);//否则直接返回strcmp的值就行了,这就是按字典序排序
}

 

各位看了这道题以后应该大概就明白qsort有多好用了(用冒泡写起来应该不容易),下面我大概介绍这个函数的一些内容(随便看看就好,有些也不重要

qsort函数简介

首先qsort其实是Quicksort也就是快速排序的缩写(qsort函数在C语言中是在<stdlib.h>这个函数库里,要使用时记得#include<stdlib.h>

其实大家在学习排序的过程中,肯定会先学过冒泡排序和选择排序

那为什么还要学qsort函数呢?

下面简单说一下,以冒泡排序为例

大家在用冒泡排序的时候肯定感觉挺麻烦的(每次都要套一下模板,而且如果涉及多关键字排序(比如又要根据字典序排序,又要根据学号排序,又要根据分数排序等等),冒泡写起来会很复杂

同时冒泡排序虽然是一个稳定的排序,但是它的平均时间复杂度其实达到了O(n^2)(而且你在写的时候还要用仔细思考一下判断条件,实在是有些麻烦;

于是接下来我就再来介绍一下快速排序和qsort;

首先快速排序虽然是一种不稳定的排序,但是它快啊!,快排的时间复杂度平均能达到O(nlogn)(虽然其他的一些归并排序什么的也能达到这个排序速度,但是函数库里没有现成的给你用qsort直接拿来用还是很香的,而且qsort对于多个变量排序时十分方便(只要你学会结构体的相关知识),而且在一些什么字典序排序时只需要return strcmp()就可以了,能大大的减小你在排序时的思维难度

嗯,下面正式介绍qsort函数

 首先qsort函数里面需要传递4个参数
 大概是这样void qsort(void *base,size_t num,size_t width,int (*cmp)(const void *p,const void *q)){
 }

1.先解释一下这个,首先第一个void *base,表示一个不确定类型的指针,所以你可以传任意类型的指针进去,比如double类型的数组,int类型的数组,或者结构体指针进去(这里说一下,比如int a[50],你可以直接传a进去,表示从a[0]开始排序,如果改成a+1就是从a[1]开始排序(我一般喜欢传a+1进去,看个人习惯了) 2.第二个size_t num表示你需要排序的元素的个数,也就是从你传入的位置往后选取num个元素,然后对这num个元素进行排序 3.size_t width 这个表示一个元素的大小,就拿上面那个数组的例子,就传a[0]进去就行了 4.int (*cmp)(const void *p,const void *q),这是一个函数指针,这个表示传入一个int类型的比较函数(一般就返回1或-1,就根据这个返回值来确定比较的大小关系),然后cmp函数接收的参数是两个不确定类型的指针(主要是防止中间把指针类型更改了,所以const 不可少,就当套路记下来吧),然后这两个指针之后需要强制类型转换(转换的类型其实就是你排序元素的类型),下面我会给例子的

然后这个qsort的实现原理大家感兴趣的话可以自己上网去搜索一下,我这里具体就不细说了(上面的东西看不懂也没关系,下面看例子就明白了)

qsort的排序规则是根据cmp函数的返回值来确定的

默认的规则是升序排序(从小到大)排序,cmp函数返回正数表示a大于b,返回负数表示a小于b,

也就是比如你比较c和d两个元素的大小,如果返回1就表示c大于d也就是会把c往后排

同时很关键的一点,不少写法中会在cmp函数中 使用 return (*(int *)c- *(int *)d)来表示返回值,

当然int类型不会有问题,但是如果是double类型的话,由于浮点数的误差会导致排序时出现一些错误

所以建议大家统一用下面的三目运算符进行cmp函数的书写 (比如 return c>d?1:-1)//这个就是升序排序,如果需要降序排序就把1和-1换个位置就好了

这是一个具体的简单例子,比如我要对a数组的前10项从小到大排序

 #include<stdio.h>
 #include<stdlib.h>
 int a[50];
 int cmp(const void *p,const void *q){//const void *p的写法背下来就行了
     int c=*(int *)p;//这里表示用c接受p指针所存的值
     int d=*(int *)q;//这里表示用d接受q指针所存的值
     
     if(c!=d){//这里用if判断一下,也就是c和d不相等时才返回1或-1; 
         return c>d?1:-1;//用三目运算符来进行值得返回
     }
     
     return 0;//返回0就表示两个数相等
 }
 int main (){
     for(int i=1;i<=10;++i){
         scanf("%d",&a[i]);
     }
     qsort(a+1,10,sizeof(a[0]),cmp);
     for(int i=1;i<=10;++i) printf("%d ",a[i]);
     return 0;
 }

大家可以试着自己先跑一下这个,熟悉一下qsort的写法套路;

结构体简介

接下来我大概介绍一下结构体,主要便于讲解多关键字排序;

 struct in{
     int arr[10];
     int num;
     char s[100];
 };

 这个就是对一个结构体的定义了
 上面的 in 表示对结构体的标记,可以类似为命名(主要是拿来区分不同的结构体)
 然后大括号内表示的就是,一个结构体变量所包含的元素:
 以这个为例,一个结构体变量里面有一个int类型长度为10的数组,还有一个int类型变量num,还有一个长度为100的字符串s

下面我给个结构体变量的定义

 struct in{
     int arr[10];
     int num;
     char s[100];
 }a[100];//写在末尾表示开了100个这样的结构体,每个结构体里面都包含有一个int类型数组,字符串s,int类型变量num

还有一种

struct in{
     int arr[10];
     int num;
     char s[100];
 };
 struct in a[100];

大家有兴趣还可以去了解一下typedef。

大概给个例子

 typedef struct in{
     int arr[10];
     int num;
     char s[100];
 }std;
 std a[100];

其实就是把struct in这一串缩写成std,能少打几个字母。

好了,下面再讲一下结构体的引用(主要以结构体变量的方式给出

比如我想使用第一个结构体元素中的num变量

int n;
 n=a[1].num//这里结构体变量引用其中元素就直接用“.”就可以引用,结构体指针才用->

 

如果想引用其中的字符串

char str[100];
 strcmp(str,a[1].s);

 

cmp函数模板

这里我再介绍一下qsort函数一个关键的部分

cmp函数!(其实命名成什么都可以,传到qsort里面就行了

比如我现在随便给个例子,就比如:

给一个50个人的班级的期末考试(只有语数英三科)从大到小排名,先排总分,总分一样排语文,依次排数学和英语,最后排一下姓名的字典序

 
//先开一个结构体
 struct in{
     int Chinese;
     int Math;
     int English;
     int sum;//总分
     char name[15];
 }a[52];
 //接下来写cmp函数
 int cmp(const void *p,const void *q){
     struct in c=*(struct in*)p;
     struct in d=*(struct in*)q;
     if(c.sum!=d.sum){//排总分
         return c.sum>d.sum?-1:1;//c的总分高就排返回-1,排到前面去
     } else if(c.Chinese!=d.Chinese) return c.Chinese>d.Chinese?-1:1;//排语文
     else if(c.Math!=d.Math) return c.Math>d.Math?-1:1;//排数学
     else if(c.English!=d.English) return c.English>d.English?-1:1;//排英语
     else return strcmp(c.name,d.name); //排姓名
 }

 

嗯,这个就差不多是多关键字排序了,其实就是结构体多添几个变量,cmp函数里面多写几个if else 而已hh;

最后需要注意的是,cmp中的const void *p,const void *q最好不要改,就当作约定俗成;

还有关于里面c和d两个变量的定义

就看你qsort传进去的是什么类型;

例题及代码

最后再贴一道例题吧

 

 例题代码:

#include<stdio.h>
 #include<stdio.h>
 #include<math.h>
 #include<string.h>
 #include<stdlib.h>
 int read();
 struct In
 {
     int num;
     int a[12];
 }s[1005];
 int cmp(const void *p1,const void *p2);
 int m;
 int main()
 {
   int n;
   n=read();
   m=read();
   for(int i=1;i<=n;i++)
   {
       s[i].num=i;
       for(int j=1;j<=m;j++)
       {
           s[i].a[j]=read();
       }
   }
   qsort(s+1,n,sizeof(struct In),cmp);
   for(int i=1;i<=n;i++)
   {
       printf("%d ",s[i].num);
   }
 return 0;
 }
 int read(){
 int x=0,f=1,c=getchar();
 while(c<'0'||c>'9')(c=='-')?(f=-1):0,c=getchar();
 while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
 return x*f;
 }
 int cmp(const void *p1,const void *p2)
 {
     struct In c=*(struct In*)p1;
     struct In d=*(struct In*)p2;
     int x;
     for(x=1;x<=m;x++)
     {
         if(c.a[x]==d.a[x]) continue;
         else if(x%2!=0)//奇数从小到大排序
         {
             return c.a[x]>d.a[x]?1:-1;
         }//偶数从大到小排序
         else return c.a[x]>d.a[x]?-1:1;
     }
 }

练习

洛谷练习

//这道题就拿给大家练习了(我就不给代码了,主要电脑上没存了hh),相信大家看懂上面几个例题后这个题应该不是太难

标签:教程,const,struct,int,void,qsort,C语言,排序
来源: https://www.cnblogs.com/xws66/p/16167039.html