C语言函数:qsort()函数

qsort函数是C语言中用于对任意类型数组进行排序的函数,它接受四个参数,包括数组起始地址、元素个数、元素大小和一个自定义比较函数。自定义函数的返回值决定了元素的排序方式,返回正数表示交换元素,负数则不交换,0表示元素相等。文章通过举例解释了如何使用qsort对整型数组和结构体数组进行排序,并展示了如何通过调整比较函数实现升序或降序排列。
摘要由CSDN通过智能技术生成

C语言函数:qsort()函数

原型:

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

头文件:<stdlib.h>

刚开始学习qsort函数时,总是不明白qsrot的作用,以及它的意义。深刻学习后,发现只是几个关键点没找到,以至于联系不起来。

qsort函数是对任意类型数组 进行排序,这是很关键的点。

先来看看,qsort函数的参数部分:

  1. void *base :首先是类型void,说明是任何类型,第一个元素需要传递的是 数组首元素地址

  1. size_t nitems :size_t我们都知道他是整形,第二个元素需要传递的是 数组元素的个数

  1. size_t size :第三个元素需要传递的是 一个元素的大小(单位:字节)

  1. int (*compar)(const void *, const void*) :可以看到这是一个函数指针类型,需要传递一个 自定义的函数

接下来,解释一下为什么要传递这四个参数,它们的作用是什么呢?

数组首元素地址:

刚刚提到,qsort函数,是对数组进行排序,我们如果拿到数组首元素地址,那么就有办法找到后面的元素,从而确定一整个数组。

数组元素个数:

要确定一个数组,元素个数一定是必须的。没有元素个数,也就无法确定一个数组。

数组元素大小:

同样地,确定一个数组,有了首元素地址、元素个数,肯定也需要元素的大小,因为有了元素大小,才知道下一个元素再哪里,从而确定一个数组。

自定义函数:

这里是qsort函数至关重要,也是初学者卡壳的地方。其实这里并不难,只是没有找到点子而已。

首先,我们需要知道,函数的返回值确定了数组的排序,qsort函数叫做:快速排序,其原理其实和冒

泡排序有点小相似,简单解释一下冒泡排序:

假如我们要将9 8 7 6 5 4 3 2 1 这个序列变成升序,使用冒泡排序:

冒泡排序就是:前一个和后一个进行比较,如果前一个比后一个 大 那么就交换。

这就是一趟冒泡排序。

一趟冒泡排序结束后,进行下一趟,接着比较.这就是冒泡排序.

回归正题,其实qsort函数也是前一个和后一个进行交换,前提是满足了某个条件,而这个条件就在于qsort函数最后一个参数,也就是需要传递的 函数 就是两个元素交换的条件.

所谓的条件,其实指的就是 传递给qsort的函数的 返回值。

这里写给脑子比较混乱的你:传给这个函数的两个元素,qsort函数会依次将传给qsort函数的数组的元素放进去。

那么就说一下返回值:

(这个函数的返回值类型一定是int类型!)

  1. 返回 0 --> 此时的两个元素 位置不变

  1. 返回 正数-->此时的两个元素 位置交换

  1. 返回 负数-->此时的两个元素 位置不变

对于返回值也会有误解:

返回0:说明此时给qsort给函数的 这两个元素,相等.因此就不用交换

返回正数:说明此时给qsort给函数的 这两个元素,不相等,qsort函数内定义了如果返回值为正数的时候 交换。此时的这两个元素就就进行交换,因此再数组内的两个元素的 位置 就进行了交换。

可以理解为,qsort函数就是让数组变成升序,如果此时返回如果是正数,就说明前一个比后一个大,这样是倒序,不行!要升序!所以交换两个元素

返回负数:说明此时给qsort给函数的 这两个元素,不相等。与返回正数的时候相反,返回的是负数,所以前一个比后一个小,满足了升序的要求!那么就不用交换了。

接下来就举个例子,相信看完举的例子后的你一定会掌握qsort函数!

例子一:

因为qsort函数可以排序任意类型的数组,所以先试着排序简单的数组:“整形数组”

首先创建了一个数组,以及计算了它的元素个数

再创建一个用于传给qsort函数的函数cmp()

传给qsort函数的函数创建 类型和形参 除了名字能改,其他一律不能修改!

因为传递给cmp函数的是指针所以要解引用.

在这里,传递给qsort函数的数组是int类型的,则数组里的所有元素都是int类型的,那么qsort函数将数组内的元素给cmp函数,那么cmp接收的每个元素也就都是int类型。cmp函数本身的形参类型是void* ,而传递给cmp函数的却是int*,类型不一样,可能占用的大小就会不一样,那么在解引用时可能就会发生错误,所以需要强制类型转换成int*,然后再解引用

如果将数组带入e1-e2 就是 9-8=1 。正数-->交换

9-7=2。正数-->交换

...

直到

0-1=-1 负数-->不交换

例子二:

前面说了,qsort可以排序任何类型的数组,那就试试排序:"结构体数组"

创建了结构体family,有两个变量:

  1. name[20]

  1. age

创建了结构体数组home[3],并且算出了home[3]的元素个数sz

对结构体排序,对于结构体,有很多变量,但是只能一种变量来作为排序的依据,先使用age排序试试:

使用qosrt函数,并且传入,首元素地址home|元素个数sz|一个元素的大小sizeof(home[0])|自定义函数str_cmp_age

str_cmp_age函数的类型与形参部分毋庸置疑。

强制类型转换也是必要的。

其次就是将e1和e2指向年龄,以至于通过年龄来作为排序的依据。

结构体没学好的话可能对这里有一个误解,为什么不用解引用呢?

  1. 当结构体指针解引用了,想找到结构体内的内容,则需要使用 . 符号。

  1. 当直接使用结构体指针,想找到结构体内的内容,则需要使用 -> 符号。

从监视里就可以看到,它们的索引改变了

接着使用name进行排序,需要知道当对字符串进行排序时,比较的是字符的Ascll码值。

这是Ascll码表

可以看到,除了qsort传参传入的函数名部分改变了,其余都没改变。

与上面同样,先找到name。但不同的,是使用了strcmp函数。

简单介绍一下strcmp():

传入两个字符或者字符串,从第一个字符开始:

如果ascll码值相同,则返回0,找到下一个字符,并继续比较,知道找到ascll码值为0的时候,也就是遇到'\0'时,停止,如果全部一样,那么返回0.

如果ascll码值不同,则返回比较两个字符ascll码值大小,返回两个字符ascll码值相减的结果.

例子:

"abcd"

"abce"

这两个字符串比较:

前面"abc"相同,跳过,"d"ascll:100和"e"ascll:101比较,则100-101=-1

则strcmp返回-1

最后可以看到,因为首字母都不同,那么就只会比较首字母的ascll码值:l<w<z则返回负数,而qsort函数:如果是负数就不交换,所以就得到了这样的排序。

需要注意的是:不是比较字符串ascll码值全部相加的大小!

可以看到,上面都是升序,那么如何得到降序呢?

只要知道,自定义函数返回负数那么就不交换,那么回看第一个案例:

怎么样得到负数呢?

8-9=-1

7-8=-1

6-7=-1

...

0-1=-1

可以看到后一个减去前一个就得到负数了,也就是把e1和e2交换一下位置就可以了:

同样的,看看案例二: 这里的age和上面提到的几乎没有差别。那么就看看结构体的name[20]。

其实这个很简单:

只需要将 负数改为正数,正数改为负数 不就可以了!

可以看到,这样就得到了与刚刚相反的结果了!

如果有错,希望纠错!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

srhqwe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值