运用qsort函数进行快排并使用C语言模拟qsort

qsort 函数的使用

       首先qsort函数是使用快速排序算法来进行排序的,下面我们打开官网来查看qsort是如何使用的。


这里有四个参数,首先base 是至待排序的数组的首元素的地址,num 是值这个数组的元素个数,size 是指每个元素的大小,最后是一个函数指针(用来比较两个元素的不同,其中这个函数需要有返回值,当返回值小于0时p1需要放在p2前面,等于0时p1和p2不用改变位置,当返回值大于0时,p1需要放在p2的后面)由此可见,这个函数需要我们自己去编写,然后通过函数指针来调用。

下面我们来看看qsort的实践效果:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>typedef struct Stu
{char name[20];int age;
}Stu;int cmp_array(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}int cmp_stu_name(const void* p1, const void* p2)
{return strcmp(((Stu*)p1)->name, ((Stu*)p2)->name);
}int cmp_stu_age(const void* p1, const void* p2)
{return ((Stu*)p1)->age - ((Stu*)p2)->age;
}void PrintArray(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}void PrintStu(Stu* s, int sz)
{for (int i = 0; i < sz; i++){printf("%s %d", s[i].name, s[i].age);printf("\n");}
}int main()
{Stu s[3] = { {"zhangsan",18},{"lisi",19},{"sunwu",15} };int sz = sizeof(s) / sizeof(s[0]);int arr[10] = { 4,8,5,7,9,6,2,0,1,3 };int sz2 = sizeof(arr) / sizeof(arr[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_name);PrintStu(s, sz);printf("\n");qsort(s, sz, sizeof(s[0]), cmp_stu_age);PrintStu(s, sz);printf("\n");qsort(arr, sz2, sizeof(arr[0]), cmp_array);PrintArray(arr, sz2);printf("\n");return 0;
}

使用C语言模拟qsort

       这里我们使用冒泡排序算法进行排序,使用C语言来模拟qsort函数。
       首先我们来回顾冒泡排序算法,有两个要点一个是排序的趟数,另一个是每一趟排序的次数。这里以升序为例:

void bubble_sort(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]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}

然后来模拟qsort函数呢?首先qsort函数几乎对任何数据都可以排序,所以我们的bubble_sort函数要做出相应调整,然后设计形参呢?对任何数据进行排序,也就是说数据的类型和大小都是不确定的,这样的话,我们可以使用size_t来作为数据类型,用void来接收不同类型的指针,实在不会的,我们可以参考qsort 函数来设计的。

void
base 接收待排序的首元素的地址,size_t num 和 size_t size 来接收元素个数和元素大小,最后就是最重要的函数设计了。

void bubble_sort(void* base, size_t num, size_t size, int (*compar) (const void* p1, const void* p2))

设计好形参,我们来考虑一下函数的主体部分,首先趟数是不改变的,每趟的次数也不用改变,毕竟我们还是使用冒泡排序算法,这样的话,还有最后一个就是if这个判断语句,应为我们无法直接通过像上面一样对两个数进行直接比较,我们需要调用函数来进行比较,也就是compar函数。

那有个问题,我们如何来写compar 函数的指针呢?这个指针不能大也不能小,否则就无法准确比较或者会产生越界行为,这样我们可以使用char* 为什么呢?首先我们需要两个两个数据来进行一一比较,这样我们需要知道准确的地址,必须是恰好指向每个元素的地址,而char 刚好就是一个字节,只要准确地进行指针加法运算就能得到这个元素地地址。

if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

还有个问题,我们怎么交换数据呢?其实和上面的理由差不多由于数据的类型不同,他们的大小也不同。这时我们可以使用char 因为char 是最小的数据类型了,也就是一个字节,无论数据是几个字节,都是char 的倍数也就是说都可以用一个字节的倍数来表示,这样的话,我们只需要知道数据类型的大小(size) 就可以来通过循环遍历来一个字节一个字节来进行进行交换就可以了,我们可以封装一个函数swap。

void swap(char* p1, char* p2, size_t size)
{int i = 0;while (i < size){char tmp = *(p1 + i);*(p1 + i) = *(p2 + i);*(p2 + i) = tmp;i++;}
}

那么我们最后得到的bubble_sort函数如下:

void bubble_sort(void* base, size_t num, size_t size, int (*compar) (const void* p1, const void* p2))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0){swap((char*)base + j * size, (char*)base + (j + 1) * size);}}}
}

我们来演练一下,看看效果是不是和qsort有着一样的效果:

代码如下:

#include <stdio.h>
#include <string.h>typedef struct Stu
{char name[20];int age;
}Stu;int cmp_array(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}int cmp_stu_name(const void* p1, const void* p2)
{return strcmp(((Stu*)p1)->name, ((Stu*)p2)->name);
}int cmp_stu_age(const void* p1, const void* p2)
{return ((Stu*)p1)->age - ((Stu*)p2)->age;
}void PrintArray(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}void PrintStu(Stu* s, int sz)
{for (int i = 0; i < sz; i++){printf("%s %d", s[i].name, s[i].age);printf("\n");}
}void swap(char* p1, char* p2, size_t size)
{int i = 0;while (i < size){char tmp = *(p1 + i);*(p1 + i) = *(p2 + i);*(p2 + i) = tmp;i++;}
}void bubble_sort(void* base, size_t num, size_t size, int (*compar) (const void* p1, const void* p2))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0){swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}int main()
{Stu s[3] = { {"zhangsan",18},{"lisi",19},{"sunwu",15} };int sz = sizeof(s) / sizeof(s[0]);int arr[10] = { 4,8,5,7,9,6,2,0,1,3 };int sz2 = sizeof(arr) / sizeof(arr[0]);bubble_sort(s, sz, sizeof(s[0]), cmp_stu_name);PrintStu(s, sz);printf("\n");bubble_sort(s, sz, sizeof(s[0]), cmp_stu_age);PrintStu(s, sz);printf("\n");bubble_sort(arr, sz2, sizeof(arr[0]), cmp_array);PrintArray(arr, sz2);printf("\n");return 0;
}

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

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

相关文章

Python猜数字小游戏

下面这段代码是一个简单的数字猜测游戏&#xff0c;其中计算机已经提前计算出了414 // 23的结果并存储在变量num中。然后&#xff0c;程序会提示用户来猜测这个结果。 以下是代码的主要步骤和功能&#xff1a; 初始化&#xff1a; num 414 // 23&#xff1a;计算414除以23的整…

Linux:各目录含义

简介 学习Linux各目录含义之前&#xff0c;我们首先要了解一下Filesystem Hierarchy Standard&#xff08;文件系统层次结构标准&#xff09;。 FHS FHS&#xff0c;即文件系统层次结构标准&#xff08;Filesystem Hierarchy Standard&#xff09;&#xff0c;是Linux和类Un…

深入了解Redis:配置文件、动态修改和安全设置

Redis 是一个开源的内存中数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。在使用 Redis 时&#xff0c;了解其配置选项是至关重要的。本文将详细介绍 Redis 的配置文件和常用配置项&#xff0c;并提供一些示例来说明如何设置和修改这些配置。 Redis 配置文…

基于stm32F103的座面声控台灯

1.基本内容&#xff1a; 设计一个放置在桌面使用的台灯&#xff0c;使用220v交流电供电。具备显示屏能够实时显示日期&#xff08;年、月、日和星期&#xff09;&#xff0c;时间&#xff08;小时、分钟、秒&#xff09;和温度&#xff08;摄氏度&#xff09;&#xff1b;能够通…

Python爬取天气数据及可视化分析!(含源码)

天气预报我们每天都会关注&#xff0c;我们可以根据未来的天气增减衣物、安排出行&#xff0c;每天的气温、风速风向、相对湿度、空气质量等成为关注的焦点。本次使用python中requests和BeautifulSoup库对中国天气网当天和未来14天的数据进行爬取&#xff0c;保存为csv文件&…

帆软下载PDF报错java.lang.OutOfMemoryError: Java heap space

需求:前端选择多条数据&#xff0c;点击下载按钮&#xff0c;下载帆软报表的pdf格式。 &#xff08;目前用的是帆软PDF下载接口&#xff0c;然后java转成文件流&#xff0c;前端接到后端接口的文件流&#xff0c;使用axios下载blob,再创建下载链接&#xff0c;通过link标签实现…

ArduinoTFTLCD应用

ArduinoTFTLCD应用 ArduinoTFTLCD应用硬件连接软件导入库显示数字、字符显示汉字方案1方案2 显示图片 总结 ArduinoTFTLCD应用 对于手工喜欢DIY的人来说&#xff0c;Arduino驱动的TFTLCD被很多人使用&#xff0c;此处就总结一下&#xff0c;使用的是VScode的PlatformIO插件驱动…

C# API异步方法和返回类型:提升应用程序性能和灵活性

摘要&#xff1a; 异步编程是现代应用程序开发中不可或缺的一部分。在C#中&#xff0c;异步方法允许我们在等待操作完成时继续执行其他任务&#xff0c;从而提高应用程序的性能和响应性。本文将介绍C# API异步方法的基本概念、原理和实际应用&#xff0c;并详细讨论异步方法的返…

【机器学习】实验5,AAAI 会议论文聚类分析

本次实验以AAAI 2014会议论文数据为基础&#xff0c;要求实现或调用无监督聚类算法&#xff0c;了解聚类方法。 任务介绍 每年国际上召开的大大小小学术会议不计其数&#xff0c;发表了非常多的论文。在计算机领域的一些大型学术会议上&#xff0c;一次就可以发表涉及各个方向…

RNA-Seq 笔记 [4]

***********************该笔记为初学者笔记&#xff0c;仅供个人参考谨慎搬运代码****************************** samtools 排序压缩和 featureCounts 生成基因计数表 SAM文件和BAM文件 1.SAM格式&#xff1a;是一种通用的比对格式&#xff0c;用来存储reads到参考序列的比…

2024最新算法:鳑鲏鱼优化算法(Bitterling Fish Optimization,BFO)求解23个基准函数(提供MATLAB代码)

一、鳑鲏鱼优化算法 鳑鲏鱼优化算法&#xff08;Bitterling Fish Optimization&#xff0c;BFO&#xff09;由Lida Zareian 等人于2024年提出。鳑鲏鱼在交配中&#xff0c;雄性和雌性物种相互接近&#xff0c;然后将精子和卵子释放到水中&#xff0c;但这种方法有一个很大的缺…

BUUCTF---[极客大挑战 2019]Upload1

1.题目描述 2.点开链接&#xff0c;需要上传文件&#xff0c;要求是image&#xff0c;上传文件后缀为jpg的一句话木马&#xff0c;发现被检测到了 3.换另一个木马试试 GIF89a? <script language"php">eval($_REQUEST[1])</script> 发现可以上传成功 4…

ctf_show笔记篇(web入门---文件包含)

目录 文件包含 78-79&#xff1a;最基础的文件包含&#xff0c;使用伪协议&#xff0c;大小写绕过或者通配符绕过&#xff0c;再或者使用其他方法 ​编辑80-81&#xff1a;可采用日志文件绕过或者大小写绕过&#xff08;81只能日志文件绕过&#xff09; ####80-86&#xff1…

『周年纪念』- 降生CSDN三周年的碎碎念

『周年纪念』- 降生CSDN三周年的碎碎念 缘起机缘迷茫厚积薄发 一转眼又过来一年&#xff0c;自己也已经 大四即将毕业。 感觉这一年像是开了加速键&#xff0c;仿佛一瞬就又过去了。统计了一下发现自己在过去的这一年就发布了 2篇文章&#xff0c;2022年发布了 117篇&#x…

PDF 解析问题调研

说点真实的感受 &#xff1a;网上看啥组件都好&#xff0c;实际测&#xff0c;啥组件都不行。效果好的不开源收费&#xff0c;开源的效果不好。测试下来&#xff0c;发现把组件融合起来&#xff0c;还是能不花钱解决问题的&#xff0c;都是麻烦折腾一些。 这里分享了目前网上能…

Python中的反射

在Python中&#xff0c;反射&#xff08;Reflection&#xff09;是一种动态地访问对象和调用其方法的能力&#xff0c;而不需要在编写代码时显式地知道对象的类或属性。这种机制使得代码具有更高的灵活性和可扩展性。Python通过几种内置函数提供了反射的功能&#xff0c;主要包…

机器学习中类别不平衡问题的解决方案

类别不平衡问题 解决方案简单方法收集数据调整权重阈值移动 数据层面欠采样过采样采样方法的优劣 算法层面代价敏感集成学习&#xff1a;EasyEnsemble 总结 类别不平衡&#xff08;class-imbalance&#xff09;就是指分类任务中不同类别的训练样例数目差别很大的情况 解决方案…

智能分析网关V4电瓶车检测与烟火算法,全面提升小区消防安全水平

2024年2月23日&#xff0c;南京市某小区因电瓶车停放处起火引发火灾事故&#xff0c;造成巨大人员伤亡和损失。根据国家消防救援局的统计&#xff0c;2023年全国共接报电动自行车火灾2.1万起。电瓶车火灾事故频发&#xff0c;这不得不引起我们的重视和思考&#xff0c;尤其是在…

阿里云A10推理qwen

硬件配置 vCPU&#xff1a;32核 内存&#xff1a;188 GiB 宽带&#xff1a;5 Mbps GPU&#xff1a;NVIDIA A10 24Gcuda 安装 wget https://developer.download.nvidia.com/compute/cuda/12.1.0/local_installers/cuda-repo-rhel7-12-1-local-12.1.0_530.30.02-1.x86_64.rpm s…

ZDH-大数据采集-支持KETTLE任务

目录 项目源码 预览地址 支持KETTLE介绍 新增KETTLE任务 配置调度KETTLE 重要说明 感谢支持 项目源码 zdh_web:GitHub - zhaoyachao/zdh_web: 大数据采集,抽取平台 预览地址 后台管理-登陆 用户名&#xff1a;zyc 密码&#xff1a;123456 支持KETTLE介绍 当前平台不…