本文介绍: C语言函数qsort()函数原型: void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))头文件: 刚开始学习qsort函数时,总是不明白qsrot的作用,以及它的意义。深刻学习后,发现只是几个关键点没找到,以至于联系不起来。 qsort函数是对任意类型数组 进行排序,这是很关键的点。 先来看看,qsort函数的参

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.

如果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]。

其实这个很简单

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

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

如果有错,希望纠错

原文地址:https://blog.csdn.net/srhqwe/article/details/128832484

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_19261.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注