qsort函数的介绍与使用(学会这个函数,再也不怕排序了!)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、qsort函数是什么?

二、qsort函数如何使用?

1.qsort定义

2.qsort函数的使用

总结



前言

随着C语言的学习,我们渐渐也学到了许多排序方法,这里我将介绍一个库函数qsort,他可以对拥有任意类型元素数据的数组进行排序。


一、qsort函数是什么?

qsort是一个库函数,可以直接使用,这个函数可以排序任意类型的数据,这个函数底层使用的是快速排序的方法。

二、qsort函数如何使用?

1.qsort定义

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

首先我们要知道qsort的头文件是 <stdlib.h>,使用它的时候要包含头文件。

我们可以看到,qsort一共有四个参数。那这四个参数都是什么呢?

void* base:这个参数就是要被派排序数组的第一个元素。也就是base存放的是等待排序数组的第一个元素的地址。

size_t num:这个参数表示base指向数组里边的元素个数。

size_t size:这个参数表示被排序数组中一个元素的长度,单位是字节。 比如说如果元素是整形的话,那一个元素长度就是4个字节,如果元素是字符的话,那一个元素长度就是1字节。

int(*compar)(const void*, const void*):这个参数是一个函数指针,返回类型是int型,这个函数指针指向了一个比较函数,这个比较函数用来比较数组中的两个元素。int(*compar)(const void*e1, const void*e2),就比如说e1和e2两个元素,如果e1指向的元素大于e2指向的元素,那么函数就会返回一个大于0的数字,如果e1指向的元素等于e2指向的元素,那么就会返回0,如果e1指向的元素小于e2指向的元素,那么就会返回一个小于0的数字。

 也就是说,我们在使用qsort函数的时候,也需要写一个比较函数,然后把比较函数传给qosrt,这样qosrt函数就可以按照我们的比较方法来比较并进行排序。

2.qsort函数的使用

首先我们在使用qsort之前,要知道我们要排序的数组是什么类型,这样到时候给qsort第四个参数传参的时候,才能知道要传可以比较什么类型的比较函数。比如说,我们现在要排一个整型数组:

int arr[10] = { 1,2,5,4,7,8,3,6,9,0 };

 那我们就需要写一个可以比较整形类型的比较函数。然后把函数名传给第四个参数:

int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{

}
int main()
{
	int arr[10] = { 1,2,5,4,7,8,3,6,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
	qsort(arr, sz, sizeof(arr[0]), cmp_int);//sizeof(arr[0])计算一个元素的大小
	return 0;
}

比较函数里边的e1指向一个元素,e2指向一个元素。他们两个进行比较。这个时候我们要进行比较e1和e2的大小。 

这时候我们发现*e1那里爆红了,这是为什么呢?其实原因很简单,我们发现e1和e2是什么类型的指针?他们是void*类型的指针,而这种指针只是为了存放一个地址,并不能解引用操作或者加减整数的操作,因为在设计这个qsort函数的时候,并不知道我们要对什么类型的数据进行排序,所以就使用void*的指针进行接收,他可以接受任意类型的指针。

那我们应该怎么办呢?如果想要使用void*类型的指针,我们需要对它进行强制转换类型,这里我们因为要排整形类型的元素,所以就需要把e1,e2指针强制转换成int*,就是这样*(int*)e1 ,*(int*)e2。先把他强制转换成int*,然后再对它解引用。

然后我们继续:

int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
	if (*(int*)e1 > *(int*)e2)
		return 1;
	else if (*(int*)e1 == *(int*)e2)
		return 0;
	else 
		return -1;
}

写成这样我们的比较函数就已经写完了,其实这个比较函数可以再简化一点,既然我们知道e1指向的元素大于e2指向的元素,就返回大于0的数字。相等就返回0 。小于就返回小于0的数字。那我们完全可以写成:

int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
	return *(int*)e1-*(int*)e2;
}

这样是不是也刚好满足要求。这些写完后,我们就可以打印一下数组,看一下qsort有没有帮我们排序好。

我们发现,qsort确实已经帮我们排好了,而且我们发现,qsort默认帮我们排成升序的结果。 

那如果我们想让他排降序呢?也很简单,把e1和e2换一下就可以。

int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
	if (*(int*)e2 > *(int*)e1)
		return 1;
	else if (*(int*)e1 == *(int*)e2)
		return 0;
	else 
		return -1;
}

或者

int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
	return *(int*)e2-*(int*)e1;
}

 这样就可以排成降序了。

那既然整型数组可以排序,那么不妨我们试一下对结构体数组进行排序呢?

首先,先创建一个结构体数组:

struct stu
{
	char name[20];
	int age;
};
struct stu s[3] = { {"zhang",20},{"li",18},{"wang",21} };

然后,因为结构体里边有名字还有年龄,我们这里先依据年龄大小进行排序,创建比较函数:

cmp_stu_by_age(const void* e1, const void* e2)
{
	return (*(struct stu*)e1).age - (*(struct stu*)e2).age;
}

这里和创建整形比较函数那里逻辑一样,需要先把e1和e2强制转换成结构体指针,然后相减,e1大于e2就会返回大于0的数字,e1等于e2就会返回0,e1小于e2就会返回小于0的数字。那我们看一下是否排序成功。下边是代码和运行截图:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct stu
{
	char name[20];
	int age;
};
cmp_stu_by_age(const void* e1, const void* e2)
{
	return (*(struct stu*)e1).age - (*(struct stu*)e2).age;
}
int main()
{
	struct stu s[3] = { {"zhang",20},{"li",18},{"wang",21} };
	int sz = sizeof(s) / sizeof(s[0]);//计算数组元素个数
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);//sizeof(arr[0])计算一个元素的大小
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", s[i].age);
	}
	return 0;
}

显然,排序成功。

那如果我们想依据名字进行排序呢?也不是不行

注意:这里名字是字符串,既然是字符串就不能直接使用>或者<或者==来比较。

而是应该用strcmp函数来进行比较,strcmp函数也是一个库函数,他的头文件是<string.h>。

strcmp函数如何使用呢?首先我们对strcmp函数传入两个字符串,strcmp(字符串1,字符串2),如果字符串1大于字符串2,它会返回大于0的数字。如果字符串1小于字符串2,它会返回小于0的数字,当然,如果相等,返回0;

诶,这样一看,这跟我们比较函数需要返回的不是一样吗?那就方便很多了。话不多说,看代码和运行截图:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct stu
{
	char name[20];
	int age;
};
cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp((*(struct stu*)e1).name, (*(struct stu*)e2).name);
}
int main()
{
	struct stu s[3] = { {"zhang",20},{"li",18},{"wang",21} };
	int sz = sizeof(s) / sizeof(s[0]);//计算数组元素个数
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//sizeof(arr[0])计算一个元素的大小
	for (int i = 0; i < sz; i++)
	{
		printf("%s ", s[i].name);
	}
	return 0;
}

 

字符串比较其实就是两个字符串相对应位置上的字符比较,比较字符的ASCLL码值,比如说,li和wang,这两个比较'l'和'w'。那个ASCLL码值大,那个就大,如果一样大,就找这两个第二个位置的字符进行比较。

那对字符排序也很简单,就是ASCLL码值相减,然后返回大于0,返回小于0,返回0这样比较大小。下边是ASCLL码值表:


总结

以上就是关于qsort函数的内容,这个库函数可以帮助我们快速的对各种类型的数组进行排序,提高了我们的效率,当然还有许多排序的方法,不一定这个就是最好的,我们也是需要找到最合适的来使用。如果能对您有所帮助,这是我的荣幸!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值