qsort() 讲解

qsort()

函数原型:void qsort(void*, size_t, size_t, int (*)(const void*, const void*) );

qsort,全称应该是quicksort 即快速排序(排序时间复杂度 n* log(n))。

简单概括就是 系统写好的排序函数,不需要自己去写复杂的排序算法,调用一下,数组就排好序了。

显而易见,该函数接受三个参数:
1:void* 待排序数组,排序之后的结果仍放在这个数组中
2:size_t 数组中待排序元素个数
3:size_t 各元素的占用空间大小(单位为字节)
4: int (*)(const void*, const void*) 指向函数的指针,也就是比较函数(关键)。比较函数也就是要告诉这个函数,你给的数组要按何种方式进行排序。

前三个参数没啥好说的,每次按照要求填写就好了。有意思的是最后一个参数。比较函数。通常会命名为cmp。这份代码中命名为比较sortingData,个人觉得并不是一个很好的名字,不如改成cmpData更加好理解。

那么这玩意怎么用呢。

举个栗子。

假如现在有整型数组 a[] = {2,4,3,5,1};

那么对这个数组排序,显然是要需要比较 两个整数值之间 的大小。

那么cmp函数写成如下形式:

int cmp(const void* a , const void* b)
{
    int* a_ = (int*)a;    //强制类型转换
    int* b_ = (int*)b;
    return *a_ - *b_;  
}

运行效果:
在这里插入图片描述

假如现在有字符型数组 a[] = {‘2’,‘4’,‘3’,‘5’,‘1’};

那么对这个数组排序,显然是要需要比较 两个字符值之间 的大小。

那么cmp函数写成如下形式:

int cmp(const void* a , const void* b)
{
    char* a_ = (char*)a;    //强制类型转换
    char* b_ = (char*)b;
    return *a_ - *b_;  
}

运行效果:
在这里插入图片描述

可以发现的是,cmp函数的参数列表是不变的:

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

这玩意就是比较两个元素的大小,如果左边比右边大,返回正数,反之,返回负数,如果相等,显然返回0。

任何一个排序算法都要比较大小吧。就拿冒泡排序来说:

for(int i = 0 ; i < n ; i ++){
	for(int j = 1 ; j < n-i ; j ++){
		if(a[j-1] > a[j]){		// 这玩意 就相当于 cmp 函数 用来比较大小的
			swap(a[j-1],a[j]);  // swap(x,y) 就是交换x,y的值
		}
	}
}

那么如果要从大到小排序数组呢,只要把

return *a_ - *b_;  

改成:

return *b_ - *a_;  

就完事了。

以上就是 qsort+cmp 函数的朴素用法。

但是,如果我要排序一个结构体呢。

比如某次考试,一个结构体记录了学生成绩和学号,那么需求是先按成绩从小到大排序,如果成绩相同,则按学号从小到大排序。

于是有以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct{
    int score;	// 成绩
    int id;		// 学号
}Stu;

int cmp(void* a,void* b){
    Stu* a_ = (Stu*)a;
    Stu* b_ = (Stu*)b;
    if(a_->score < b_->score){
        return -1;
    }
    if(a_->score > b_->score){
        return 1;
    }

    if(a_->id < b_->id){
        return -1;
    }
    if(a_->id > b_->id){
        return 1;
    }
}


int main()
{
    Stu stu[3];
    stu[0].id = 201802; stu[0].score = 60;
    stu[1].id = 201800; stu[1].score = 80;
    stu[2].id = 201801; stu[2].score = 60;
    qsort(stu,3,sizeof(Stu),cmp);
    for(int i = 0 ; i < 3 ; i ++){
       printf("%d: %d\n",stu[i].id,stu[i].score);
    }
    return 0;
}

或者cmp函数这么写(效果是一毛一样的):

int cmp(void* a,void* b){
    Stu* a_ = (Stu*)a;
    Stu* b_ = (Stu*)b;
    if(a_->score == b_->score){   // 如果相等则按id排序
        return a_->id - b_->id;
    }
    return a_->score - b_->score; // 负责按成绩排
}

看看效果:

在这里插入图片描述

比如再把id改成字符串呢,当然没问题,把id比较的地方改成字符串比较:

int cmp(void* a,void* b){
    Stu* a_ = (Stu*)a;
    Stu* b_ = (Stu*)b;
	return strcmp(a_->id,b_->id); // strcmp() 会返回字符串比较结果 正负值 或者 0
}

至此,你应该已经掌握了qsort+cmp的用法。

最后一个思考题,如果要按 (成绩*100+学号*3)的奇偶性排序,如果奇偶性相同按(成绩*100+学号*3) 的值排序,如果还相等,那么按成绩,最后按学号。cmp应该怎么写。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值