qsort函数详解以及模拟实现
创始人
2024-05-07 05:39:04
0

qsort函数详解以及模拟实现

  • 一.qsort函数是什么
  • 二.具体的使用
    • 1.参数4(参数3在模拟实现时解释)
    • 2.例子
      • 1.排序整形
      • 2.排序结构体
  • 三.模拟实现qsort
    • 1.参数3
    • 2.模拟排序
      • 1.排整形
      • 2.排结构体

在这里插入图片描述

一.qsort函数是什么

qsort全称为quick_sort(快速排序),为什么这么称呼呢?因为它实现的内核就是依靠快排来实现的。但与单纯的快排不同的是,它是库函数并且可以排序任意类型的数据(整数,字符,结构体,字符串…)。

接下来再MSDN里详细看看它的全貌

在这里插入图片描述

可以看到它的头文件是stdlib.h,并且参数很多接下来会详细解析。

在这里插入图片描述

在这里插入图片描述

base

第一个参数是base,在MSDN里的解释是Start of target array。也就是目标数组的开始。

第一个参数传目标数组的起始位置。

num

第二个参数是num,在MSDN里的解释是Array size in elements。也就是数组的大小。

第二个参数传数组的大小。

第三个参数是width,在MSDN里的解释是Element size in bytes。也就是每个成员的大小。

第三个参数是每个元素占的字节大小。

第四个参数是一个函数指针指向compare。在MSDN里的解释是Comparison function。也就是比较功能。

第四个参数传一个函数指针,它所指向的函数要具备比较功能。

二.具体的使用

1.参数4(参数3在模拟实现时解释)

关于函数的参数,参数1,2自然不必多说(要排序自然得知道起始位置和数组大小)。对于参数4,如果我们只需要比较整形,我们自然可以只是向上面的冒泡排序一样直接使用大于比较,但如果是一个字符串呢?如果是一个结构体呢?那么我们当然不能简单的用大于小于这些符号来比较,我们需要自己写一个判断规则,这就是参数4的意义。明确判断规则。也是qsort能排序任意类型数据的关键。

详细说明参数4需要的参数

在这里插入图片描述

1.e1是你需要比较元素的第一个元素的地址,e2是另一个元素的地址。
2.两个参数的类型都是const void *
3.const是为了防止参数在函数内部被改变
4.void*是无具体类型的指针(下面重点说明一下)

在这里插入图片描述

但对于这个函数来说肯定是需要接收不同类型的指针的,各。void*是通用指针。好处是可以接收各种指针,坏处是不能直接解引用,因为连它自己都不知道自己是什么类型。

在这里插入图片描述
在这里插入图片描述

2.例子

1.排序整形

上面说到void*不能直接解引用,所以需要我们进行强制转换。这样才能够使用。ps:由于参数4是函数指针,所以我们应该传函数地址,函数名就表示函数地址。

在这里插入图片描述

这个函数总得有返回值吧,来看看MSDN。

在这里插入图片描述

如果第一个元素小于第二个元素,返回一个小于0的数。如果相等则返回0;如果大于,则返回大于0的数。那么我们就按照它的要求书写。

在这里插入图片描述

来看看结果。

在这里插入图片描述

当然以上是升序,如果想要降序的话直接调个方向就可以了。

在这里插入图片描述

2.排序结构体

在这里插入图片描述

首先按照年龄排成升序

在这里插入图片描述

在这里插入图片描述

可以看到确实按照年龄的升序来排列的。

按照名字来排列

名字是字符串不能直接使用减号,需要用到strcmp。它是按照对应位置字符大小来比较的。

在这里插入图片描述

我们知道该函数需要返回数字,而恰好strcmp满足这个要求。所以我们只需要直接返回strcmp就可以了(注意头文件是string.h)。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

由于l

总结:需要排列什么数据取决于参数4所指向的函数如何判断。

三.模拟实现qsort

上文提到qsort是依托快排实现的,但由于快排有些复杂,这里就使用冒泡排序作为内核。(如果还有些不明白的可以看看这篇博客 冒泡排序)

在这里插入图片描述

这是一个简易的冒泡排序,它也能够排列数据。但与qsort不同的是,它只能排列整数。所以接下来我要改造它,使它能够排列任意数据。(ps:这里目前不考虑时间,空间,稳定性之类的)。

上文说过,qsort能排列任意数据,关键在于你写的判断函数,也就是参数4。所以我们也应当对冒泡排序的判断条件进行修改。将它封装为一个函数。

在这里插入图片描述

既然我们要模拟qsort,那么参数也应当于qsort保持一致。ps:为什么要传这些参数,开头已经说过,但参数3还未说过,接下来讲解为什么要传每个元素的宽度。

1.参数3

1.首先我们第一个参数是void * ,也就是我们根本不知道到底传递的是什么类型,我们需要参数3来确定是哪种类型。
2.方便我们找到每个元素(具体使用请看模拟过程)

2.模拟排序

在这里插入图片描述

再次说明参数4是函数指针,它所指向的函数就是我们所写的判断规则,再根据cmp的返回值,如果大于0我们就交换两个数据。接下来的关键是我们如何给cmp传参,也就是我们如何精确的找到这两个元素,然后进行判断。

冒泡排序的内核是相邻两个元素两两进行比较,所以我们com里也应该两两相邻元素进行比较。由于我们根本不知道数据类型,不能使用下标来算,需要用地址来间接寻找,这也体现出了参数3的作用。

在这里插入图片描述

在这里插入图片描述

接下来是如何交换,由于类型不明,我们肯定不能直接交换。但是无论什么元素它的单位都是字节,那么我们可以一个字节一个字节的交换,写一个交换函数挨个交换它们的字节。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

以上就是模拟实现的qsort,任意数据都可以排序,接下来来验证一下。

1.排整形

在这里插入图片描述

2.排结构体

按年龄

在这里插入图片描述

按名字

在这里插入图片描述

总结:由于qsort需要适合各种类型,所以我们传参除了部分明确的外都是void。qsort如何精确的找到两个数依赖于数据的地址。不同类型数据的比较方法是不同的,所以需要我们自己写判断规则。

在这里插入图片描述

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...