qsort使用举例和qsort函数的模拟实现

qsort使用举例

qsort是C语言中的一个标准库函数,用于对数组或者其他数据结构中的元素进行排序。它的原型如下:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

我们可以去官网搜来看一看:

那么对于其中的参数,下面也有相应的英文解释:

- base:指向要排序的数组或数据结构的第一个元素的指针。
- nmemb:要排序的元素的数量。
- size:每个元素的大小(以字节为单位)。
- compar:指向用于比较两个元素的函数的指针。

compar函数用于比较两个元素的大小关系,返回值为整数,表示两个元素的大小关系。具体返回值的含义如下:
- 若返回值小于0,则表示第一个元素小于第二个元素。
- 若返回值等于0,则表示两个元素相等。
- 若返回值大于0,则表示第一个元素大于第二个元素。

qsort函数根据compar函数的返回值对数组或数据结构中的元素进行排序,可以按照升序或降序进行排序。
那么知道以上这些,下面我们就来使用这个库函数,首先我们以排序整型数组为例:

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

假设我们要排列以上的10个元素,那么我们根据上面对于库函数qsort的认识,需要向它传入四个参数,那么第一个为- base:指向要排序的数组或数据结构的第一个元素的指针,那么就是我们的arr 了,第二个为- nmemb:要排序的元素的数量,这是我们就要计算里面有多少个元素了,我们可以这样算:

int sz = sizeof(arr) / sizeof(arr[0]);

使用第二个参数我们可以写为  sz ,第三个为- size:每个元素的大小,那么我们计算出数组中第一个元素有多少个字节就可以了 sizeof(arr[0]),最后一个为- compar:指向用于比较两个元素的函数的指针,这里我们就需要我们自己写一个函数了,告诉这个库函数qsort我们要比较什么类型的数据:

qsort(arr, sz, sizeof(arr[0]), cop_int);

那么接下来就是这个cop_int函数怎么写了,因为我们不知道会传什么样的数据,所以我们可以使用void*进行接收,返回类型为int型,因为下面是根据大于或小于或等于来排序的,而且不希望改我们所要排序的数值,所以我们这样写到:

int cop_int(const void* p1, const void* p2)

上面传来了void*类型的数据,而void*的数据不能够直接进行运算操作,所以下面我们要进行强制类型转换,作差看看两数的情况:

return *(int*)p1 - *(int*)p2;

下面就来看看我们整体的代码:

#include <stdlib.h>//头文件void Print_arr(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}int cop_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}int main()
{int arr[10] = { 4,5,7,6,3,2,8,9,1,10 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cop_int);Print_arr(arr, sz);return 0;
}

看看我们的运行效果:

 下面我们给结构体进行排序:

我们先随便写一个结构体:

struct Stu
{char name[20];int age;int score;
};//定义一个学生的名字,岁数,分数

我们只需要改我们的- compar:指向用于比较两个元素的函数的指针,我们先以学生的名字进行排序,那么结构体我们只需要转换成结构体指针就可以进行比较了,名字我们strcmp进行比较:

#include <stdlib.h>//qsort的头文件
#include <string.h>//strcmp的头文件
struct Stu
{char name[20];int age;int score;
};
int cop_Stu_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name , ((struct Stu*)p2)->name);
}
int main()
{struct Stu arr[] = { {"zhangsan",18,76},{"lisi",28,65},{"wangmazi",25,79}};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cop_Stu_by_name);for (int i = 0; i < sz; i++){printf("%s %d %d\n", arr[i].name, arr[i].age,arr[i].score);}return 0;
}

看看运行的结果:

 是正确的哦!我们还可以以年龄进行比较还有分数啊,这里我就不排了,我们下面用冒泡排序来qsort函数的模拟实现!

qsort函数的模拟实现(采用冒泡排序法)

对于冒泡排序,我在前面也写到过,还不太清楚的小伙伴可以看看哦。

void BubbleSort(int arr[], int sz)
{for (int i = 0; i < sz - 1; i++)//趟数{for (int j = 0; j < sz - 1 - i; j++)//一趟冒泡排序{if (arr[j] > arr[j + 1])//需要进行改造的地方 1{int tmp = arr[j];// 需要进行改造的地方 2arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}int main()
{int arr[] = { 5,7,9,4,3,6,8,1 };//5 7 9 4 3 6 8 1int sz = sizeof(arr) / sizeof(arr[0]);//计算有多少个元素BubbleSort(arr, sz);for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

首先我们先来想一想,那些地方需要我们改造,对于循环那些我们是不是就不用改了,那不会有影响。我们将会排序到不同的数据类型,所以我们对于 if (arr[j] > arr[j + 1])的比较,是不是需要我们进行改造呢,还有下面的交换变量,也是我们需要改的,既然上面的类型都被改了,下面也肯定是需要改的。

我们以结构体的年龄为例,那么函数的参数还是我们上面的那样,只是要改一下第四个参数:

bubble_sort2(arr, sz, sizeof(arr[0]), cop_Stu_by_age);

接下来就是对于bubble_sort2函数的定义了,下面传了四个参数,那我们也要用四个参数进行接收了,因为我们不知道传来的是什么类型的,所以在设置类型上,我们要考虑考虑,第一个为地址,我们用void*进行接受吧,void*都装的了,哈哈。第二个和第三个就用size_t了,最后一个像我们上面考虑的那个样:int (*cmp)(const void* p1, const void* p2)。

void bubble_sort2(void* base,size_t sz,size_t width, int (*cmp)(const void* p1, const void* p2))
{for (int i = 0; i < sz-1; i++){for (int j = 0; j < sz-1-i; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}

接着就是对于比较的改造了,我们这里构造一个新的函数进行比较,这样我们根据下面传来的类型去调用相应的,那么我们怎样找到我们的对应的元素进行比较呢?下面给给了我们首元素的地址,和每个元素的大小,我们是不是可以用起来呢,我们根据j的变化去找到元素。但是还要想到我们要用它来不同数据类型的排序,所以我们也要进行强制类型转换。我们强制转换成什么类型的数据呢?是不是char*最为合适呢,不管是什么类型,我们都可以一个一个的去进行交换:

if(cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)

下面我们进行对于交换的改造:上面改成了那样,所以接收时也改成相应的就行了,我们以前进行交换的时候是创建了第三个变量进行交换,现在我们不知什么类型,就需要改进了。强制转换成什么类型比较合适呢?假设我们结构体的为7个字节大小,那我们是不是用char类型就可以了,不管你如何,我一个一个的进行交换就都可以实现,既然我们以这样的方式进行实现,那我们是不是应该把它每个元素的大小传进来呢:

void swap(char* a, char* b, size_t width)
{for (int i = 0; i < width; i++){char tmp = *a;*a = *b;*b = tmp;a++;b++;}
}

接下来我们就看看整体的代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>struct Stu
{char name[20];int age;
};int cop_Stu_by_age(const void* p1, const void* p2)
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}int cop_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void PrintArr(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void swap(char* a, char* b, size_t width)
{for (int i = 0; i < width; i++){char tmp = *a;*a = *b;*b = tmp;a++;b++;}
}//冒泡排序
void bubble_sort2(void* base,size_t sz,size_t width, int (*cmp)(const void* p1, const void* p2))
{for (int i = 0; i < sz-1; i++){for (int j = 0; j < sz-1-i; j++){//if (arr[j] > arr[j + 1])if(cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width,width);/*int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;*/}}}
}int main()
{struct Stu arr[] = { {"aihua",18},{"zhanghong",21},{"kiki",15} };int sz = sizeof(arr) / sizeof(arr[0]);//年龄bubble_sort2(arr, sz, sizeof(arr[0]), cop_Stu_by_age);for (int i = 0; i < sz; i++){printf("%s %d\n", arr[i].name, arr[i].age);}return 0;
}

看看运行结果:

 那么也是可以的哟,我这里就是用其他类型进行排序了,感兴趣的话,可以去试试哦,本来还想着画图给你们梳理一下,可那个画图工具不给力😢😢😢!

愿你们冬不寒!❤❤❤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lxml基本使用

lxml是python的一个解析库&#xff0c;支持HTML和XML的解析&#xff0c;支持XPath解析方式&#xff0c;而且解析效率非常高 XPath&#xff0c;全称XML Path Language&#xff0c;即XML路径语言&#xff0c;它是一门在XML文档中查找信息的语言&#xff0c;它最初是用来搜寻XML文…

2024全网最新最全的Pytest接口自动化测试框架教程

pytest编写的规则&#xff1a; 1、测试文件以test_开头&#xff08;以_test结尾也可以&#xff09; 2、测试类以Test开头&#xff0c;并且不能带有__init__方法 3、测试函数以test_开头 4、断言必须使用assert pytest.main([-s,-v]) &#xff1a;用来执行测试用例 -s 打印prin…

卷积神经网络(CNN)天气识别

文章目录 前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;我的环境&#xff1a; 2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 可视化数据3. 再次检查数据4. 配置数据集 三、构建CNN网络四、编译五、训练模型六、模型评估 前期工作 1. 设置GP…

EEPROM与Flash的区别

EEPROM与Flash的区别 EEPROMEEPROM内部功能框图实现写入数据内部结构存储管在充电或放电状态下有着不同的阈值电压 问题点EEPROM是如何失效的呢&#xff1f;为何EEPROM不能做大呢&#xff1f; ------------------------------------------------------------------------------…

Java多线程(3)

Java多线程(3) 深入剖析Java线程的生命周期&#xff0c;探秘JVM的线程状态&#xff01; 线程的生命周期 Java 线程的生命周期主要包括五个阶段&#xff1a;新建、就绪、运行、阻塞和销毁。 **新建&#xff08;New&#xff09;&#xff1a;**线程对象通过 new 关键字创建&…

tamarin运行

首先我们找到安装tamarin的文件位置&#xff0c;找到以后进入该文件夹下 ubuntuubuntu:~$ sudo find / -name tamarin-prover /home/linuxbrew/.linuxbrew/var/homebrew/linked/tamarin-prover /home/linuxbrew/.linuxbrew/Cellar/tamarin-prover /home/linuxbrew/.linuxbrew/…

mac下vue-cli从2.9.6升级到最新版本

由于mac之前安装了 vue 2.9.6 的版本&#xff0c;现在想升级到最新版本&#xff0c;用官方给的命令&#xff1a; npm uninstall vue-cli -g 发现不行。 1、究其原因&#xff1a;从vue-cli 3.0版本开始原来的npm install -g vue-cli 安装的都是旧版&#xff0c;最高到2.9.6。安…

基于Netty实现的简单聊天服务组件

目录 基于Netty实现的简单聊天服务组件效果展示技术选型&#xff1a;功能分析聊天服务基础设施配置&#xff08;基于Netty&#xff09;定义组件基础的配置&#xff08;ChatProperties&#xff09;定义聊天服务类&#xff08;ChatServer&#xff09;定义聊天服务配置初始化类&am…

后端接口错误总结

今天后端错误总结&#xff1a; 1.ConditionalOnExpression(“${spring.kafka.exclusive-group.enable:false}”) 这个标签负责加载Bean&#xff0c;因此这个位置必须打开&#xff0c;如果这个标签不打开就会报错 问题解决&#xff1a;这里的配置在application.yml文件中 kaf…

Linux Docker图形化工具Portainer如何进行远程访问?

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

Flutter最新稳定版3.16 新特性介绍

Flutter 3.16 默认采用 Material 3 主题&#xff0c;Android 平台预览 Impeller&#xff0c;DevTools 扩展等等 欢迎回到每季度一次的 Flutter 稳定版本发布&#xff0c;这次是 Flutter 3.16。这个版本将 Material 3 设为新的默认主题&#xff0c;为 Android 带来 Impeller 预览…

SpringBoot使用DevTools实现后端热部署

&#x1f4d1;前言 本文主要SpringBoot通过DevTools实现热部署的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&…

Windows使用ssh远程连接(虚拟机)Linux(Ubuntu)的方法

步骤 1.Windows下载一个SSH客户端软件 要使用SSH连接&#xff0c;当然得先有一个好用的客户端软件才方便。 我这里使用的是WindTerm&#xff0c;一个开源免费的SSH连接工具&#xff0c;用什么软件不是重点。 这里默认你已经生成过SSH的密钥了&#xff0c;如果没有&#xff0c…

C语言 字符函数汇总,模拟实现各字符函数(炒鸡详细)

目录 求字符串长度 strlen 示例 模拟实现strlen 长度不受限制的字符串函数 strcpy 示例 模拟实现strcpy strcat 模拟实现strcat strcmp 示例 模拟实现strcmp 长度受限制的字符串函数介绍 strncpy 示例 模拟实现strncpy strncat 示例 模拟实现strncat s…

Spring Boot 中使用 ResourceLoader 加载资源的完整示例

ResourceLoader 是 Spring 框架中用于加载资源的接口。它定义了一系列用于获取资源的方法&#xff0c;可以处理各种资源&#xff0c;包括类路径资源、文件系统资源、URL 资源等。 以下是 ResourceLoader 接口的主要方法&#xff1a; Resource getResource(String location)&am…

【Hello Go】Go语言异常处理

Go语言异常处理 异常处理error接口panicrecover延时调用错误问题 异常处理 error接口 Go语言引入了一个关于错误处理的标准模式 它是Go语言内建的接口类型 它的定义如下 type error interface {Error() string }Go语言的标准库代码包errors为用户提供了以下方法 package e…

人工智能轨道交通行业周刊-第65期(2023.10.30-11.19)

本期关键词&#xff1a;高铁自主创新、智慧城轨、调车司机、大模型垂直应用、大模型幻觉 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道…

Kafka快速入门

文章目录 Kafka快速入门1、相关概念介绍前言1.1 基本介绍1.2 常见消息队列的比较1.3 Kafka常见相关概念介绍 2、安装Kafka3、初体验前期准备编码测试配置介绍 bug记录 Kafka快速入门 1、相关概念介绍 前言 在当今信息爆炸的时代&#xff0c;实时数据处理已经成为许多应用程序和…

汽车虚拟仿真视频数据理解--CLIP模型原理

CLIP模型原理 CLIP的全称是Contrastive Language-Image Pre-Training&#xff0c;中文是对比语言-图像预训练&#xff0c;是一个预训练模型&#xff0c;简称为CLIP。该模型是 OpenAI 在 2021 年发布的&#xff0c;最初用于匹配图像和文本的预训练神经网络模型&#xff0c;这个任…

【Ubuntu】设置永不息屏与安装 dconf-editor

方式一、GUI界面进行设置 No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal打开 Ubuntu 桌面环境的设置菜单。你可以通过点击屏幕右上角的系统菜单&#xff0c;然后选择设置。在设置菜单中&#xff0c;…