【C语言进阶篇】回调函数都学了吧!那么用冒泡排序实现qsort函数你会嘛?


在这里插入图片描述

🎬 鸽芷咕:个人主页

 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》

⛺️生活的理想,就是为了理想的生活!

文章目录

  • 📋 前言
  • 💬 qsort 和 冒泡排序的区别
        • 📑 qsort 的特点
        • 📑 冒泡排序 的特点
    • 💭 如何解决只能排序整形
        • 📖(void *)指针讲解
        • 📖(void* )类型的指针该如何使用
      • ✅ 解决方法
    • 💭 如何解决只能排序整形
      • 📖 冒泡排序需要改进的地方
        • ✅ 改进方法
        • ✅ 参数讲解
    • 💭 如何解决不同类型的交换问题
        • ✅ swap交换函数的实现
  • 💬 bubble_sort实现完全体
    • 💭 bubble_sort完整代码
        • 🌈 测试排序整形数组
        • 🌈 测试排序结构体
  • 📝全篇总结

📋 前言

  🌈hello! 各位宝子们大家好啊,前面一章讲解了qsor快排函数的使用那么我们是否可以自己实现一下他呢?
  ⛳️冒泡排序我们都知道只能排序整形,但是回调函数学完了之后就可以完美解决这个问题,下面就来看看吧!
  📚本期文章收录在《C语言进阶篇》,大家有兴趣可以看看呐
  ⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!

🔥 注:VS2022 等C语言学习工具都在《学习工具专栏》, 还有各种实用调试技巧有兴趣可以去看看呐!

💬 qsort 和 冒泡排序的区别

📑 qsort 的特点

🔥 注:快排函数qsort的使用博主在《qsort的使用详解》详细讲解过哦,不会可以去看看。

qsort的特点是:

  • 可以排序任意类型的数据
  • 使用快速排序的思想 quick

📑 冒泡排序 的特点

冒泡排序 的特点:

  • 只能排序整形数据

冒泡排序 思想:

  • 俩俩相邻的元素进行比较,满足条件就交换

好了这俩种排序的思想和区别我们都明白了!冒泡排序我相信大家都不陌生,那么我们今天的任务就是使用冒泡排序的思想去模拟实现库函数qsort 函数的功能!

  • 而这需要解决冒泡排序3个缺陷
  • 一、只能排序整形
  • 二、不同类型的数据比较方法不一样
  • 三、不同类型数据如何交换方法也不一样

💭 如何解决只能排序整形

这个是冒泡排序最主要的问题,那么改如何解决呢?既然是模拟实现qsort 函数那么我们就可以借鉴一下 qsort 函数的方法!

  • qsort 函数里面直接用 通用类型指针 接收的数据
  • 通用类型指针 是不是刚好能解决冒泡排序只能接收整数的问题
    在这里插入图片描述

📖(void *)指针讲解

void我们都知道是一个空类型的意思,void 就是无类型的指针 :*

  • 无具体类型的指针,可以说他为通用类型指针
  • 但是这种类型的指针是不能够直接进行解引用操作的
  • 由于类型是空类型所以也不能进行指针运算
  • 因为既然他是个空类型那么我们 + - 是该跳过多少字节呢?

📚示例一:
在这里插入图片描述

  ⛳️这里就就可以看出一旦指针类型不同是不可以接收不同类型的地址的!

  • 而用 void* 类型的指针就不会出现这种情况

📚示例二:
在这里插入图片描述

📖(void* )类型的指针该如何使用

  ⛳️前面说了这种指针既不能直接解引用,又不能进行指针运算那么我们该怎么使用void*类型的指针呢?

  • 🌱 其实void*类型的指针在使用的时候需要强制转换一下就好了!
  • 🌱 这样这个空指针类型不就有类型了(我们强制转换的类型)
  • 🌱 那么指针的运算不也解决了?因为有类型了就可以知道
  • 🌱 加一步我们可以跳过多少字节

📑图片展示:
在这里插入图片描述

✅ 解决方法

现在我们知道了 qsort 快排函数的参数 和 通用类型指针 void* 如何使用那么解决冒泡排序只能排序整形还不简单嘛?

  • 既然是模拟实现 qsort 那么就先仿着 qsort 的参数写
  • 来实现我们的冒泡排序 bubble_sort
    在这里插入图片描述

📚 代码演示:

//模拟实现 qsort 
void bubble_sort(void* base, //第一个参数的地址size_t num,//要比较元素的个数size_t size, //比较元素的大小int (*cmp)(const void* , const void*) )//比较函数的地址

这里我们就把要模拟实现的函数 bubble_sort 的参数给写好了,由于我们也要排序不同类型的参数所以,肯定是需要元素类型大小

  • 从哪里排序的第一个参数地址
  • 以及要排序多少个元素
  • 和每个元素怎么进行比较

💭 如何解决只能排序整形

大家都知道冒泡排序在比较整数的时候字需要简单的进行比个大小就好了。但是我们这里需要对不同类型进行比较就不能进行以前那种简单的比较方法了!

  • 那么该怎么解决呢?这个其实也很简单 qsort
  • 库函数里面需要我们自己写一个比较函数来进行判断如何比较
  • 那么我们也可以使用这种方法,对于不同的数据由使用者来决定如何比较
  • 我们只需要调用就好了。

📖 冒泡排序需要改进的地方

在这里插入图片描述

✅ 改进方法

📚 代码演示:

这里我们可以怎么改进呢?前面说了对于不同的数据由使用者来决定如何比较!我们只需要写一个回调函数就好了!

  • 使用回调函数就可以在这里解决问题
  • 一个函数可以调用多种不同的函数

🔥 注: 回调函数的详细讲解和使用实例在这里《回调函数的实战技巧》

void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* , const void*) )
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if ( cmp((char*)base+j*size, (char*)base +( j +1)* size)>0){int tmp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = tmp;}}}
}

✅ 参数讲解

cmp((char*)base+jsize, (char)base +( j +1)* size)>0
这个函数调用是如何写出来的呢? 虽然我们的比较函数是由使用者来实现的!但是我们只是可以调用函数,而函数的参数还是需要我们在 bubble_sort 里面传出去的。

  • 既然要比较就需要 第一个 第二个 俩个相邻的元素
  • void* 类型的指针又不能直接使用,我们还要排序不同类型的元素所以类型转换就不能写死
  • 把它强转为 (char*) 是最合理的,一个字节!

而我们又知道每个元素的类型大小是多少,这不就和巧妙嘛!(char*)base+j*size char* 指针是每次访问一个字节,那么乘上我们的元素类型大小就刚好可以访问不同类型的元素!

  • 假设我们参数是整形数组
  • 那么 (char*)base+j*size 就是访问4个字节(char*)base+j*4
  • 刚好是一个整形的大小。

💭 如何解决不同类型的交换问题

而冒泡排序以前的交换算法也肯定不可取了,这就需要我们自己构建一种可以交换任意类型的数据了!
在这里插入图片描述

✅ swap交换函数的实现

既然是交换那么肯定需要俩个参数,所以 (char*)base+j*size(char*)base +( j +1)* size) 这俩个参数肯定是需要的

  • 而我们传过来的参数是强转成 char* 的
  • 那么我们是不是可以这样交换
    在这里插入图片描述

一个字节一个字节的进行交换,诶是不是很神奇。这样是不是也能把俩个元素个相互交换并且内容都不发生改变。

  • 因为交换的本质还是一样,只不是以前是一步完成的!
  • 我们现在交换了4次,只是次数变多了但结果是一样的!
  • 都是把不同字节的内容给交换了!
  • 只需要知道要交换元素类型大小是多少,所以我们还需要一个类型大小 size 传过来!

📚 代码演示:

//交换函数
void swap(char* p1, char* p2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}

💬 bubble_sort实现完全体

好了这下我们冒泡排序的所有缺点都解决了,折现就可以验证一下 bubble_sort 冒泡排序模拟实现的 qsort 在功能上是不是一样的!

💭 bubble_sort完整代码

📚 代码演示:

//交换函数
void swap(char* p1, char* p2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}//测试 bubble_sort 整数排序
//void qsort(void* base, size_t num, size_t size,//int (*compar)(const void*, const void*))
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* , const void*) )
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if ( cmp((char*)base+j*size, (char*)base +( j +1)* size)>0){swap((char*)base + j * size, (char*)base + (j + 1) * size,size);}}}
}

🌈 测试排序整形数组

📚 代码演示:

#include <stdio.h>
#include <string.h>//交换函数
void swap(char* p1, char* p2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}//测试 bubble_sort 整数排序
//void qsort(void* base, size_t num, size_t size,//int (*compar)(const void*, const void*))
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* , const void*) )
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if ( cmp((char*)base+j*size, (char*)base +( j +1)* size)>0){swap((char*)base + j * size, (char*)base + (j + 1) * size,size);}}}
}
//整形比较函数
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1) - (*(int*)p2);
}test1()
{int arr[10] = { 1,9,5,3,4,2,10,8,7,6 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), int_cmp);//打印函数}int main()
{test1();return 0;
}

🌈 测试排序结构体

📚 代码演示:

#include <stdio.h>
#include <string.h>struct stu
{char name[20];int		age;
};//交换函数
void swap(char* p1, char* p2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}//测试 bubble_sort 整数排序
//void qsort(void* base, size_t num, size_t size,//int (*compar)(const void*, const void*))
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* , const void*) )
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if ( cmp((char*)base+j*size, (char*)base +( j +1)* size)>0){swap((char*)base + j * size, (char*)base + (j + 1) * size,size);}}}
}//结构体比较函数
int struct_cmp(const void* p1, const void* p2)
{return strcmp( ((struct stu*)p1)->name,((struct stu*)p2)->name);
}//测试排序结构体
void test2()
{struct stu arr[3] = { {"zhangsan",20},{"lisi",40},{"wangwu",33} };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), struct_cmp);
}
int main()
{test2();return 0;
}

📝全篇总结

✅ 归纳:
好了以上就是关于模拟实现qsort 函数的全部讲解了,学会这些你就可以完美的使用回调函数!
  qsort函数和冒泡排序的区别
  只能排序整形的改进方法
  判断部分的改进
  交换函数的实现
  测试数据
☁️ 以上就全部内容了,本章是对回调函数的应用和提高大家学会了嘛!
看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖
拜托拜托这个真的很重要!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。
在这里插入图片描述

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

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

相关文章

56. 合并区间

题目描述 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;inter…

JS逆向之猿人学爬虫第20题-wasm

文章目录 题目地址sign参数分析python算法还原往期逆向文章推荐题目地址 https://match.yuanrenxue.cn/match/20第20题被置顶到了第1页,题目难度 写的是中等 算法很简单,就一个标准的md5算法,主要是盐值不确定, 而盐值就在wasm里面,可以说难点就在于wasm分析 sign参数分…

[Linux]进程间通信

[Linux]进程间通信 文章目录 [Linux]进程间通信进程间通信什么是进程间通信进程间通信的目的进程间通信的本质为什么存在进程间通信进程间通信的分类 管道什么是管道匿名管道本质pipepipe的使用匿名管道读写情况匿名管道的特征 命名管道本质命令行创建命名管道创建和删除命名管…

如何在电脑上查看连接过的wifi信息?

忘记wifi密码&#xff1f;想要看看wifi信息&#xff1f; 我想这篇文章可以帮到你O(∩_∩)O哈哈~。 通过网络连接中心查看 电脑上找到“网络和共享中心” 点击连接的wifi名称 点击无线属性 在安全选项中就有密码 通过电脑命令行工具查看推荐 通过winr快捷键打开电脑运…

随手笔记——根据点对来估计相机的运动综述

随手笔记——根据点对来估计相机的运动综述 说明计算相机运动 说明 简单介绍3种情况根据点对来估计相机运动所使用的方法 计算相机运动 有了匹配好的点对&#xff0c;接下来&#xff0c;要根据点对来估计相机的运动。这里由于相机的原理不同分为&#xff1a; 当相机为单目时…

剑指YOLOv5改进主干EfficientNet模型:重新思考卷积神经网络的模型扩展,YOLOv5提升性能

💡本篇内容:剑指YOLOv5改进主干EfficientNet模型:重新思考卷积神经网络的模型扩展,YOLOv5提升性能 💡🚀🚀🚀本博客 改进源代码改进 适用于 YOLOv5 按步骤操作运行改进后的代码即可 💡:重点:该专栏《剑指YOLOv5原创改进》只更新改进 YOLOv5 模型的内容 💡…

vim工具 windows系统使用

vim常用命令&#xff1a; 编辑–>输入&#xff1a; i: 在当前光标所在字符的前面&#xff0c;转为输入模式&#xff1b; 粘贴命令 p p: 如果删除或复制为整行内容&#xff0c;则粘贴至光标所在行的下方&#xff0c;如果复制或删除的内容为非整行&#xff0c;则粘贴至光标所…

手动搭建gateway,项目集成gateway实现Token效果

目录 背景步骤1、首先创建springboot项目2、引入依赖3、配置文件&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff08;超级重要&#xff01;&#xff01;&#xff01;根据自己的需要进行配置&#xff09;4、相关类我们在服务中进行的白名单中接口的操作如…

信驰达推出RTL8720DN系列2.4G和5G双频Wi-Fi+蓝牙二合一模块

近日&#xff0c;领先的无线物联网通信模块厂商深圳信驰达科技RF-star推出了基于RTL8720DN SoC的2.4 GHz和5 GHz双频Wi-Fi蓝牙二合一模块—RF-WM-20DNB1。 图 1信驰达RF-WM-20DNB1 Wi-Fi模块 RF-WM-20DNB1是一款低功耗单芯片无线蓝牙和Wi-Fi组合模块&#xff0c;支持双频(2.4 G…

详细介绍如何使用HuggingFace和PyTorch进行医学图像分割-附源码

医学图像分割是一种创新过程,使外科医生能够拥有虚拟的“X 射线视觉”。它是医疗保健领域非常有价值的工具,可提供非侵入性诊断和深入分析。考虑到这一点,在这篇文章中,我们将探索威斯康辛大学麦迪逊分校胃肠道图像分割Kaggle 挑战数据集。作为该项目的一部分,我们将使用 …

爬虫005_python类型转换_其他类型转换为整型_转换为Float类型_转换为字符串_转换为布尔值---python工作笔记023

首先来看,字符串转换成int 很简单 float转换成int 会把小数点后面的内容丢掉 boolean转换为int true是1 false 是0 然后字符串转换为int,要注意 不能有特殊字符比如1.23 中有点 就报错 上面字符串12ab,有ab也报错 看上面

Docker可视化管理工具Portainer多机器安装使用

一、首先得安装docker Docker安装并指定主目录:https://blog.csdn.net/wdy_2099/article/details/77367107 二、使用docker方式安装portainer 安装命令如下&#xff1a; docker run -it -d \-p 8999:9000 \--name portainer \--restart always \-v /var/run/docker.sock:/v…

googlenet论文理解

参考文章&#xff1a;https://www.cnblogs.com/czy4869/p/8977788.html 以及下面这篇的前几行让我弄懂了论文里说的稀疏性和计算性能兼顾&#xff1a;参考文章&#xff1a;https://blog.csdn.net/weixin_52121118/article/details/119740279

Linux Ubuntu crontab 添加错误 提示:no crontab for root - using an empty one 888

资料 错误提示&#xff1a; no crontab for root - using an empty one 888 原因剖析&#xff1a; 第一次使用crontab -e 命令时会让我们选择编辑器&#xff0c;很多人会不小心选择默认的nano&#xff08;不好用&#xff09;&#xff0c;或则提示no crontab for root - usin…

海外腾讯云账号:腾讯云高性能计算平台 THPC

高性能计算平台&#xff08;TencentCloud High Performance Computing&#xff0c;THPC&#xff09;是一款腾讯云自研的高性能计算资源管理服务&#xff0c;集成腾讯云上的计算、存储、网络等产品资源&#xff0c;并整合 HPC 专用作业管理调度、集群管理等软件&#xff0c;向用…

Apache Impala教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Impala是由Cloudera开发&#xff0c;一个开源的Massively Parallel Processing&#xff08;MPP&#xff09;查询引擎 。与Apache Hive相同的元数据、SQL语法、ODBC驱动程序和用户接口(Hue Beeswax)&#xff0c;可以直接在HDFS或HBase上提供快速、交互式SQL查询。Impa…

Drupal教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Drupal是使用PHP语言编写的开源内容管理框架&#xff08;CMF&#xff09;&#xff0c;它由内容管理系统&#xff08;CMS&#xff09;和PHP开发框架&#xff08;Framework&#xff09;共同构成&#xff0c;在GPL2.0及更新协议下发布。连续多年荣获全球最佳CMS大奖&…

【Python入门系列】第二十篇:Python区块链和加密货币

文章目录 前言一、区块链基础知识1.1 什么是区块链1.2 区块链的工作原理 1.3 区块链的优势和应用场景二、Python实现区块链2.1 创建区块类2.2 创建区块链类2.3 添加区块和验证区块链 三、加密货币基础知识3.1 什么是加密货币3.2 加密货币的工作原理3.3 加密货币的挖矿和交易 四…

【图像分类】CNN + Transformer 结合系列.1

介绍三篇结合使用CNNTransformer进行学习的论文&#xff1a;CvT&#xff08;ICCV2021&#xff09;&#xff0c;Mobile-Former&#xff08;CVPR2022&#xff09;&#xff0c;SegNetr&#xff08;arXiv2307&#xff09;. CvT: Introducing Convolutions to Vision Transformers, …

Windows bat 查找文件被哪个进程占用,并终止该进程

一、背景 我有个批处理脚本如下&#xff1a; echo off chcp 936 & cls cd /D F:\Chen\python3\ExciseC set fdate%date:~0,4%%date:~5,2%%date:~8,2% python main.py >> crawl_record_%fdate%.log 2>&1 for /F %%f in (dir crawl_record_*.log /B ^| find /…