【落羽的落羽 C语言篇】指针·之其五
文章目录
- 一、冒泡排序
- 二、qsort排序
- 1. qsort使用指南
- 2.回调函数
- 3. qsort函数的模拟实现
一、冒泡排序
冒泡排序的核心思想就是:两两相邻的元素进行比较和交换。
现在,我们想编写一个函数,使它能够运用冒泡排序的原理,由小到大排好一个乱序的整形数组。例如:假如输入5、2、1、10、9、7、3、4、8、6,能输出1、2、3、4、5、6、7、8、9、10。如果画图分许这个排序过程的每一步:
看,经过第一轮的两两比较,较大的数排到右边,这样最大的10就来到了最右边。
而经过第二次排序,第二大的9就能来到倒数第二个位置。
像这样继续排序,这个数组的大小是10,经过9次(10-1次)排序,就能完成1到10的排序。
知道了原理,在代码层面编写这样的函数就非常简单了:
void bubble_Sort(int* p ,int sz)
{
for(int turn=1 ; turn<=sz-1 ; turn++)//要排n个数字,就需要进行n-1轮排序for(int i=0 ; i<sz-1 ; i++)if(p[i] > p[i+1]){int tmp = p[i];p[i] = p[i+1];p[i+1] = tmp;}
}
当然,为了节省运行时间,我们还可以进行一点优化:假如这个数组在第一趟排序后就已经有序了,它就可以直接停止而没必要再排序好多次。
void bubble_Sort(int* p ,int sz)
{
for(int turn=1 ; turn<=sz-1 ; turn++)
{int flag = 1;//假设这一次已经有序了for(int i=0 ; i<sz-1 ; i++){if(p[i] > p[i+1]){flag = 0;//发生了交换说明这一次还不是有序int tmp = p[i];p[i] = p[i+1];p[i+1] = tmp;}}if(flag==1)break;//这一次没有发生交换,说明已经有序了,可以退出函数了
}
}
这样,整个程序就是:
#include<stdio.h>
void bubble_Sort(int* p ,int sz)
{
for(int turn=1 ; turn<=sz-1 ; turn++)
{int flag = 1;for(int i=0 ; i<sz-1 ; i++){if(p[i] > p[i+1]){flag = 0;int tmp = p[i];p[i] = p[i+1];p[i+1] = tmp;}}if(flag==1)break;
}
}int main()
{
int arr[10]={0};
for(int i=0 ; i<10 ; i++)scanf("%d",&arr[i]);
bubble_Sort(arr, sizeof(arr)/sizeof(arr[0]));
for(int i=0 ; i<10 ; i++)printf("%d ",arr[i]);
return 0;
}
结果也是非常的成功~
二、qsort排序
1. qsort使用指南
冒泡排序只能用来排序整型数字,而且写起来太麻烦了。如果我们有了一组数据,想要直接快速按某种方式排序,该怎么办呢?
乂~C语言提供了一个库函数qsort,可以按照你想要的方式排序各种类型的数据,使用它需要包含头文件stdlib.h
在链接https://legacy.cplusplus.com/reference/clibrary/中,我们可以查到:
借助翻译:
不理解也没关系,简言之,qsort函数的语法形式是:
void qsort(void* base, size_t num, size_t size, int(*compar)(const void*,const void*));
其中:
- base指针指向的是待排序数据中的第一个元素
- num是待排序数据的个数
- size是待排序数据中的每一个元素的字节大小
- compar是一个函数指针,这个函数用来比较base指向的数据中任意两个元素的大小
注意:compar函数需要使用者自己提供,也就是要自己提供比较数据的方式。这个函数有两个参数(也就是要比较的两个元素),需要返回一个整型数。
不要着急,我们先来个简单的栗子:用qsort函数排序一个整型乱序数组:
#include<stdlib.h>
#include<stdio.h>
int compar_int(const void* p1, const void* p2)
{
return ( *(int*)p1 - *(int*)p2 );
//p1和p2一开始是void*指针,但是实际上他们指向的都是整型数据,所以要(int*)强制类型转换
}int main()
{
int arr[] = {5,2,1,10,9,7,3,4,8,6};//待排序数组
int sz = sizeof(arr)/sizeof(arr[0]);
qsort(arr, sz, sizeof(int), compar_int);
//arr:第一个元素的地址
//sz:元素个数
//sizeof(int):每个元素的字节大小
//compar_int:用来比较的函数的地址
for(int i=0 ; i<sz ; i++)printf("%d ",arr[i]);
return 0;
}
很完美的结果。
但我们不禁思考,这个qsort函数是怎么依靠compar函数实现交换和排序的呢?
其实,qsort函数每次比较compar函数的两个参数,这两个指针参数指向的是任意的元素,依靠compar函数的返回值判断是否要交换:
- 返回值为负,就把p1指向的元素放在p2指向的元素后面;
- 返回值为0,不交换;
- 返回值为正,就把p1指向的元素放在p2指向的元素前面。
(这里“前”指的是数组下标较大的位置,“后”是下标较小的位置)
所以,上面的程序能实现由小到大的排序,而如果你想由大到小排,只需要把compar_int里的return ( *(int*)p1 - *(int*)p2 );
改为return ( *(int*)p2 - *(int*)p1 );
就可以了:
不光是整型,如果我们想把一个字符数组按照ASCII的大小排序,也可以使用qsort函数:
#include<stdlib.h>
#include<stdio.h>
int compar_char(const void* p1, const void* p2)
{
return ( *(char*)p1 - *(char*)p2 );
//p1和p2一开始是void*指针,但是实际上他们指向的都是字符型数据,所以要(char*)强制类型转换
}int main()
{
char arr[] = {'b','t','m','a','a','x'};//待排序数组
int sz = sizeof(arr)/sizeof(arr[0]);
qsort(arr, sz, sizeof(char), compar_char);
for(int i=0 ; i<sz ; i++)printf("%c ",arr[i]);
return 0;
}
2.回调函数
回调函数的概念很简单,它就是一个通过函数指针调用的函数。
如果你把函数的地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数了。回调函数不是由该函数的实现方直接调用的,而是在特定的条件下由另一方调用的,用于对该条件进行响应。
3. qsort函数的模拟实现
首先我要说的是,后期我们还会学习到很多的函数,他们都有不同的功能,但我们不仅要学会使用他们,还应该学会模拟实现这些函数。所谓模拟实现,是创造一个自己的函数,传递原函数相同的参数,也要能达到原函数的效果。今天,我们也应该学会模拟实现qsort函数。定义一个函数void Mine_qsort(void* base, size_t num, size_t size, int(*compar)(const void*,const void*));
这就是我模拟实现的qsort函数。
而具体交换思路呢,可以分为比较、交换两步,运用了回调函数的概念和冒泡排序的思想。
#include<stdio.h>
int compar_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}void swap(const void* p1, const void* p2)
{
int tmp = *((int*)p1);
*((int*)p1) = *((int*)p2);
*((int*)p2) = tmp;
}void Mine_qsort(void* base, size_t num, size_t size, int(*compar)(const void*,const void*))
{
for(int turn=1 ; turn<=num-1 ; turn++)for(int i=0 ; i<num-1 ; i++)if(compar( (int*)base+i, (int*)base+i+1 ) > 0)swap( (int*)base+i, (int*)base+i+1 );
}int main()
{
int arr[]={2,6,4,10,5,3,1,8,7,9};
Mine_qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(int), compar_int);
for(int i=0 ; i<10 ; i++)printf("%d ",arr[i]);
return 0;
}
这样,我们就模拟实现了qsort函数
然鹅,我的代码只能排序整型数组,如果要排序其他类型数据,也可以采用另外一种通法:一个字节一个字节地交换,这样能突破不同数据类型大小不同的限制。感兴趣的各位可以自行研究~
欲知后事如何,且听下回分解~
本篇完,感谢阅读
相关文章:

【落羽的落羽 C语言篇】指针·之其五
文章目录 一、冒泡排序二、qsort排序1. qsort使用指南2.回调函数3. qsort函数的模拟实现 一、冒泡排序 冒泡排序的核心思想就是:两两相邻的元素进行比较和交换。 现在,我们想编写一个函数,使它能够运用冒泡排序的原理,由小到大排…...
go的web框架介绍
Go 语言有许多优秀的 Web 框架,适用于不同类型的 Web 应用开发,涵盖从简单的 API 开发到复杂的微服务架构。以下是一些常见的 Go Web 框架: 1. Gin 简介:Gin 是一个高性能的 Go Web 框架,设计目标是让开发者能够以极…...

基于群晖搭建个人图书架-TaleBook based on Docker
前言 在群晖Container Manager中部署失败,转通过ssh部署。 一、准备工作 名称备注群晖SSH“终端机和SNMP”中启用SSH软件secureCRT等docker-compose.ymlGithub下载并修改 二、过程 2.1 创建本地文件夹 本地路径为: /docker/Calibre/data 2.2 下载d…...
redis哨兵安装部署
1、下载redis安装包,上传到3台服务器上 redis.tar.gz 解压处理 2、分别编译安装 cd redis/src make make install 3、配置哨兵模式 修改redis.conf文件内容 主节点 和 从节点都需要修改 bind 0.0.0.0 -::1 或者真实的ip地址 protected-mode no port 637…...

JVS低代码里表单与表格不同数据关联场景的实现方法
在业务处理与数据管理中,表单与表格模型的数据关联及同步保存是一个常见的需求。特别是在涉及多个数据模型且字段存在关联或差异时,合理设计表单与表格之间的数据交互逻辑特别重要。接下来小编以JVS低代码系统为例,详细介绍两种不同场景下&am…...

NaviveUI框架的使用 ——安装与引入(图标安装与引入)
文章目录 概述安装直接引入引入图标样式库 概述 🍉Naive UI 是一个轻量、现代化且易于使用的 Vue 3 UI 组件库,它提供了一组简洁、易用且功能强大的组件,旨在为开发者提供更高效的开发体验,特别是对于构建现代化的 web 应用程序。…...

Cannot resolve symbol ‘ActivityThread‘ | Android 语法
背景 ActivityThread 是 Android 系统内部使用的一个类,它位于 android.app 包中,但在 Android SDK 的公共 API 中并没有公开。 由于 ActivityThread 是隐藏的内部类,因此在编写单元测试或功能开发时,无法直接引用它。可以使用反射来访问内部 API,或者使用依赖注入的方式…...

OpenSSH-9.9p1 OpenSSL-3.4.0 升级步骤详细
前言 收到漏洞扫描通知 OpenSSH 安全漏洞(CVE-2023-38408) OpenSSH 安全漏洞(CVE-2023-51385) OpenSSH 安全漏洞(CVE-2023-51384) OpenSSH 安全漏洞(CVE-2023-51767) OpenSSH 安全漏洞(CVE-2023-48795) OpenSSH(OpenBSD SecureShell)是加拿大OpenBSD计划…...

python 练习题
目录 1,输入三个整数,按升序输出 2,输入年份及1-12月份,判断月份属于大月,小月,闰月,平月,并输出本月天数 3,输入一个整数,显示其所有是素数因子 4&#…...

数学建模——Topsis法
数模评价类(2)——Topsis法 概述 Topsis:Technique for Order Preference by Similarity to Ideal Solution 也称优劣解距离法,该方法的基本思想是,通过计算每个备选方案与理想解和负理想解之间的距离,从而评估每个…...

Electron-vue 框架升级 Babel7 并支持electron-preload webapck 4 打包过程记录
前言 我这边一直用的electron-vue框架是基于electron 21版本的,electron 29版本追加了很多新功能,但是这些新功能对开发者不友好,对electron构建出来的软件,使用者更安全,所以,我暂时不想研究electron 29版…...

github仓库自动同步到gitee
Github Actions是Github推出的自动化CI/CD的功能,我们将使用Github Actions让Github仓库同步到Gitee 同步的原理是利用 SSH 公私钥配对的方式拉取 Github 仓库的代码并推送到 Gitee 仓库中,所以我们需要以下几个步骤 生成 SSH 公私钥添加公钥添加私钥配…...

汽车仪表板可识别安全气囊,安全带,ABS,邮箱,灯等多种告警参数,YOLO,VOC,COCO三种方式标记的数据集整理
关于数据集介绍: 汽车仪表板可识别安全气囊,安全带,ABS,邮箱,灯等多种告警参数,YOLO,VOC,COCO三种方式标记的数据集。 可识别常见的: 安全气囊和安全带系统 ,…...

springboot370高校宣讲会管理系统(论文+源码)_kaic
毕 业 设 计(论 文) 高校宣讲会管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,…...

GoReplay开源工具使用教程
目录 一、GoReplay环境搭建 1、Mac、Linux安装GoReplay环境 二、GoReplay录制与重播 1、搭建练习接口 2、录制命令 3、重播命令 三、GoReplay单个命令 1、常用命令 2、其他命令 3、命令示例 4、性能测试 5、正则表达式 四、gorepaly组合命令 1、组合命令实例 2、…...

UE4_材质节点_有关距离的_流体模拟
一、材质节点介绍: 特别注意:距离场需要独立显卡支持。 1、什么是距离场? 想象一下空间中只有两个实体, 一个球,一个圆柱. 空间由无数个点组成, 取其中任何一个点, 比如,它跟球面的最近距离是3, 跟圆柱面的最近距离是2, 那么这个点的值就…...
虚拟现实(VR)与增强现实(AR)有什么区别?
虚拟现实(Virtual Reality,VR)与增强现实(Augmented Reality,AR)在多个方面存在显著差异。以下是对这两者的详细比较: 一、概念定义 虚拟现实(VR): 是一种…...
浏览器中输入一个URL后,按下回车后发生了什么
URL ,统一资源定位符, 简单点就是网址 ip 或域名 端口号 资源位置 参数 锚点 大致流程 URL 解析DNS 查询TCP 连接处理请求接受响应渲染页面 1 .输入一个网址之后,首先浏览器通过查询 DNS ,查找这个 URL 的 IP …...
GNOME(GNU Network Object Model Environment)
定义与概述 GNOME(GNU Network Object Model Environment)是一种广泛使用的桌面环境。它是一个自由软件项目,旨在为操作系统提供一个直观、易用且功能强大的图形用户界面(GUI)。GNOME主要运行在类UNIX操作系统上&#…...
源码分析之Openlayers中的Collection类
概述 在Map类中,有一种高频出现的类Collection(即集合),比如Map类中interaction、controls和overlay的定义初始化和一些操作调用都和Collection有关。本文主要介绍 Openlayers 中Collection类的实现以及Collection类的事件机制。 源码剖析 Collection类 Collection类本质…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...