库函数qsort 的模拟实现

news/2024/9/20 1:38:55/

在之前了解了库函数qsort的使用之后 我们来模拟实现一下

上篇有介绍 qsort的底层实现是快速排序 由于害怕没有人了解过快速排序 我就用大家熟知的冒泡排序进行模拟实现

先来展示完整代码 以下代码为升序排序 如果降序将冒泡排序中的大于号改为小于号就可以了

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>int my_cmp(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void Swap(char* buf1, char* buf2, int width)
{for (int i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}void my_qsort(void* base, size_t num, size_t width, int (*my_cmp)(const void* p1, const void* p2))
{for (size_t i = 0; i < num - 1; i++){for (size_t j = 0; j < num - i - 1; j++){if (my_cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}
void Print(int* arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{int arr[] = { 7,4,1,8,5,2,9,6,3 };int sz = sizeof(arr) / sizeof(arr[0]);Print(arr, sz);my_qsort(arr, sz, sizeof(arr[0]), my_cmp);Print(arr, sz);return 0;
}

解释以上代码

void my_qsort(void* base, size_t num, size_t width, int (*my_cmp)(const void* p1, const void* p2))
{for (size_t i = 0; i < num - 1; i++){for (size_t j = 0; j < num - i - 1; j++){if (my_cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}

我们可以看出 在参数中 base(数组arr首元素地址) 是void*类型的 所以没有大小 那么我们就不能对voide*指针变量作加减操作 如果要作加减必须强制转化为其他的指针类型(具有大小的指针类型)

那我们这块为什么要用char*进行强制类型转换 因为他的大小只有一个字节 适合便利传过来的数组的各种类型 (数组类型的大小无非就是char*指针进行堆积的效果吗)所以用它进行访问最合适了

my_cmp是我们要传的函数指针 (char*)base + j*width 是该数组元素地址的起始地址 第二的参数是数组第二个元素的起始地址 传过去的就是一个char*大小的指针(理解这块 这块是核心)

那么如何交换两个元素呢

我们交换了两个元素的地址 不就交换了 两个元素了吗 接下来就是怎样交换两个元素的地址

void Swap(char* buf1, char* buf2, int width)
{for (int i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}

bud1,buf2就是传过来元素地址的首字节 将数组元素占的地址一一交换

就是这样的实现方式

最后代码的运行结果如下

以上就是qsort的实现 如果掌握其他排序方式 也可以用来实现~


http://www.ppmy.cn/news/29985.html

相关文章

【设计模式之美 设计原则与思想:设计原则】19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?

关于 SOLID 原则&#xff0c;我们已经学过单一职责、开闭、里式替换、接口隔离这四个原则。今天&#xff0c;我们再来学习最后一个原则&#xff1a;依赖反转原则。在前面几节课中&#xff0c;我们讲到&#xff0c;单一职责原则和开闭原则的原理比较简单&#xff0c;但是&#x…

「媒体分流直播」媒体直播和传统直播的区别,以及媒体直播的特点

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好直播毋庸置疑已经融入到了我们生活的方方面面&#xff0c;小到才艺&#xff0c;游戏&#xff0c;大到政策的发布&#xff0c;许多企业和机构也越来越重视直播&#xff0c;那么一场活动怎么最大化的进行传播&#xff0c;一是…

【基础算法】单链表的OJ练习(3) # 移除链表元素 # 相交链表 #

文章目录前言移除链表元素相交链表写在最后前言 本章的OJ练习也是相对简单的&#xff0c;只要能够理解解题的思路&#xff0c;并且依照这个思路能够快速的写出代码&#xff0c;我相信&#xff0c;你的链表水平已经足够了。 对于OJ练习&#xff08;2&#xff09; : ->传送门…

x86 平台利用 qemu-user-static 实现 arm64 平台 docker 镜像的运行和构建

文章目录[toc]关于 docker 版本查看是否开启 experimental 功能开启 experimental 功能查看当前环境平台拉取一个 arm 平台的容器运行一个 arm 平台的容器整一个 qemu-user-static注册可支持的架构解释器尝试启动 arm64 镜像尝试启动 ppc64le 镜像后台运行 arm64 容器build 一个…

java @Autowired @Resource @Inject 三个注解的区别

javax.annotation.Resourcejdk 内置的&#xff0c;JSR-250 中的注解。依赖注入通过 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor 来处理。org.springframework.beans.factory.annotation.Autowired org.springframework.beans.factory.annotati…

【算法设计-枚举、分治】素数、约数、质因数分解

文章目录1. 素数判定2. 素数筛选法3. 质因数分解4. 求一个数的约数5. 求两个数的最大公约数&#xff08;GCD&#xff09;6. 求两个数的最小公倍数&#xff08;LCM&#xff09;1. 素数判定 判定从 2 到sqrt(n)依次能否把 n 整除&#xff0c;若存在可以整除的数则说明 n 不是素数…

ZincSearch Java 客户端教程

ZincSearch Zinc 简单、强大&#xff0c;不了解的同学可以参见我之前的博客。今天我们这里谈谈 Java 环境如何集成 Zinc 客户端&#xff0c;跟如何使用的。 安装 Zinc 到 Github 的官方 Releases 下载&#xff1a; 我的是 Windows 开发环境&#xff0c;下载 zincsearch_0.4…

Spring Cloud融合Nacos配置加载优先级 | Spring Cloud 8

一、前言 Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置&#xff1a; A&#xff1a;通过内部相关规则(应用名、扩展名、profiles)自动生成相关的 Data Id 配置B&#xff1a;通过 spring.cloud.nacos.config.extension-configs的方式支持…

Python 基础语法

文章目录条件判断循环数据类型变量字符编码字符串格式化listtupledictset不可变对象”#“ 开头的是注释每一行是一个语句&#xff0c;当语句以冒号 “:” 结尾时&#xff0c;缩进的语句被视为代码块 好处&#xff1a;强迫代码格式化&#xff0c;强迫少用缩进 坏处&#xff1a;“…

用Python写个猜数字游戏,写游戏难道比玩游戏还好玩(12)

小朋友们好&#xff0c;大朋友们好&#xff01;我是猫妹&#xff0c;一名爱上Python编程的小学生。欢迎和猫妹一起&#xff0c;趣味学Python。今日主题开学差不多有1个月了吧&#xff1f;猫妹刚刚从寒假的玩玩玩模式切换到上学的学学学模式。你呢&#xff1f;这是猫妹的课程表&…

【8】【用户操作日志】操作日志SpringBootStarter

操作日志 此版本操作日志主要就是通过AOP拦截器实现的&#xff0c;整体主要分为AOP拦截器、自定义函数、日志上下文、扩展接口&#xff1b;组件提供了6个扩展点&#xff0c;自定义函数、日志上下文、用户信息获取&#xff0c;日志保存&#xff0c;自定义异常获取&#xff0c;入…

Android性能调优 - 省电优化

省电&#xff1a;通过工具Battery Historian查看到:耗电大头: 屏幕、网络、cpuled/oled屏幕显示:降低亮度&#xff0c;开深色模式&#xff1b;锁屏间隔缩短到 &#xff1b;亮屏需要一直持有唤醒锁&#xff0c;还有gps定位也需要用到唤醒锁;网络&#xff1a; 常用的网络优化措施…

详解进程 及 探查进程

进程的概念PCB是什么task_struct的作用如何执行进程进程的探查什么是bashps命令的使用&#xff08;查看进程&#xff09;创建进程探究父子进程进程的概念 简而言之&#xff0c;进程就是正在在执行的程序 之前说过&#xff0c;程序执行的第一步Windows是双击程序Linux是 ./ &a…

【uni-app教程】UniAPP 常用组件和 常用 API 简介# 知心姐姐聊天案例

五、UniAPP 常用组件简介 uni-app 为开发者提供了一系列基础组件&#xff0c;类似 HTML 里的基础标签元素&#xff0c;但 uni-app 的组件与 HTML 不同&#xff0c;而是与小程序相同&#xff0c;更适合手机端使用。 虽然不推荐使用 HTML 标签&#xff0c;但实际上如果开发者写了…

Java 循环语句

Java 循环语句 循环语句就是在满足一定条件的情况下反复执行某一个操作的语句。Java中提供了3种常用的循环语句&#xff0c;分别是while循环语句、do…while循环语句和for循环语句。 1.while循环语句 while语句也称条件判断语句&#xff0c;它的循环方式为利用一个条件来控制…

MyBatis框架的入门案例

MyBatis框架的入门案例 资源地址&#xff1a;https://download.csdn.net/download/weixin_41957626/87531373 1.MyBatis的配置 环境&#xff1a;基于maven的结构 1.1目录结构 1.2依赖包 <dependencies><!--mybatis--><dependency><groupId>org.mybatis…

C#开发的OpenRA的游戏主界面怎么样创建

通过前面加载界面布局数据,可以把整个界面逻辑的数据加载到内存, 但是这些数据怎么显示出来,又是没有定义的。比如前面定义了多个界面的布局, 又是怎么样知道需要显示哪一个界面? 现在就来解决这个问题,其实整个游戏都是可以通过yaml文件进行配置的, 所以我们需要从yaml…

Spring面试专题

讲师&#xff1a;邓澎波 Spring面试专题 1.Spring应该很熟悉吧&#xff1f;来介绍下你的Spring的理解 1.1 Spring的发展历程 先介绍Spring是怎么来的&#xff0c;发展中有哪些核心的节点&#xff0c;当前的最新版本是什么等 通过上图可以比较清晰的看到Spring的各个时间版本…

C++---最长上升子序列模型---拦截导弹(每日一道算法2023.3.4)

注意事项&#xff1a; 本题为"线性dp—最长上升子序列的长度"的扩展题&#xff0c;这里只讲贪心思路&#xff0c;dp去这个看。 题目&#xff1a; 某国为了防御敌国的导弹袭击&#xff0c;发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷&#xff1a;虽然它…

centos安装rocketmq

centos安装rocketmq1 下载rocketmq二进制包2 解压二进制包3 修改broker.conf4 修改runbroker.sh和runserver.sh的JVM参数5 启动NameServer和Broker6 安装rockermq dashboard(可视化控制台)1 下载rocketmq二进制包 点击rocketmq二进制包下载地址&#xff0c;下载完成之后通过ft…