运用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,一经查实,立即删除!

相关文章

基于stm32F103的座面声控台灯

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

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

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

ArduinoTFTLCD应用

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

【机器学习】实验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;都是麻烦折腾一些。 这里分享了目前网上能…

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

类别不平衡问题 解决方案简单方法收集数据调整权重阈值移动 数据层面欠采样过采样采样方法的优劣 算法层面代价敏感集成学习&#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介绍 当前平台不…

lv20 QT进程线程编程

知识点&#xff1a;启动进程 &#xff0c;线程 &#xff0c;线程同步互斥 1 启动进程 应用场景&#xff1a;通常在qt中打开另一个程序 process模板 QString program “/bin/ls"; QStringList arguments; arguments << "-l" << “-a";QPro…

手撕Java集合之简易版Deque(LinkedList)

在目前&#xff0c;许多互联网公司的面试已经要求能手撕集合源码&#xff0c;集合源码本身算是源码里比较简单的一部分&#xff0c;但是要在面试极短的10来分钟内快速写出一个简易版的源码还是比较麻烦的&#xff0c;很容易出现各种小问题。所以在平时就要注重这方面的联系。 以…

仓储自动化新解:托盘四向穿梭车驶入智能工厂 智能仓储与产线紧密结合

目前&#xff0c;由于对仓库存储量的要求越来越高&#xff0c;拣选、输送以及出入库频率等要求也越来越高&#xff0c;对此&#xff0c;在物流仓储领域&#xff0c;自动化与智能化控制技术得以快速发展&#xff0c;货架穿梭车在自动库领域的应用越来越广泛。现阶段&#xff0c;…

linux之进程理解(1)

目录 1. 冯诺依曼体系结构 2. 操作系统(OS) 2.1 概念 2.2 设计OS的目的 2.3 定位 2.4 理解管理 3. 系统调用和库函数概念 4. 补充 1. 冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体…

chrome选项页面options page配置

options 页面用以定制Chrome浏览器扩展程序的运行参数。 通过Chrome 浏览器的“工具 ->更多工具->扩展程序”&#xff0c;打开chrome://extensions页面&#xff0c;可以看到有的Google Chrome扩展程序有“选项Options”链接&#xff0c;如下图所示。单击“选项Options”…

制作镜像与配置推送阿里云仓库

一、制作jdk镜像 1.1、Alpine linux简介 Alpine Linux是一个轻量级的Linux发行版&#xff0c;专注于安全、简洁和高效。它采用了musl libc和BusyBox&#xff0c;使得系统资源占用较少&#xff0c;启动速度较快。 Alpine Linux也提供了一个简单的包管理工具APK&#xff0c;(注…