当前位置: 首页 > news >正文

【C语言】_使用冒泡排序模拟实现qsort函数

目录

1. 排序函数的参数

2. 排序函数函数体

2.1 比较元素的表示

2.2 交换函数Swap的实现

2.3 排序函数bubble_sort的实现

3. 测试整型数据排序

3.1 整型数据比较函数cmp_int的实现

3.2 整型数据排序后输出函数print_int的实现

3.3 整型数据测试函数test_int的实现 

3.4 完整程序及运行结果 

4. 测试结构体型数据排序

4.1 创建结构体型数据

4.2 结构体型数据比较函数cmp_stu_byxxxx的实现

4.3 结构体型数据排序后输出函数print_stu的实现

4.4 结构体型数据测试函数test_stu的实现

4.5 完整程序及运行结果


 qsort采用快排实现,现使用冒泡进行模拟实现;

 关于排序,冒泡排序实现文章参考如下:
【C语言】_冒泡排序及其优化思路-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/m0_63299495/article/details/145014576

关于qsort函数,具体使用方法文章参考如下:

【C语言】_qsort函数-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/m0_63299495/article/details/145076745

1. 排序函数的参数

void bubble_sort(void* base, // 参数1:泛型指针接收待排序数组基址size_t sz,				 // 参数2:正数变量接收待排数据个数size_t width,            // 参数3:正数变量接收单个待排数据大小int(*cmp)(const void* p1,const void* p2) 
// 参数4:函数指针变量接收待排数据大小比较函数地址、
{  }

注:理解函数指针的重要作用,正是由于函数指针cmp的实现,才实现了多种类型元素的比较;

2. 排序函数函数体

2.1 比较元素的表示

1、对于冒泡排序,比较原则为相邻元素进行比较。

对于原排整型数据的冒泡排序,可使用>=<对 arr[ j ]与arr[ j+1 ]直接进行判断;

但为实现各种类型数据的排序,则需重新编写元素比较函数cmp;

2、关于相邻元素的表示,当前待排序数组基址为base,待排序元素大小为width,

对于第 j 个与第 j+1 个元素,可将base强转为char*类型后偏移对应倍数的数据元素大小width

即表示为:(char*)base + j × width (char*)base + (j+1) × width

cmp((char*)base+j*width,(char*)base+(j+1)*width)

2.2 交换函数Swap的实现

1、对于原排整型数据的冒泡排序,可创建整型临时变量tmp对arr[ j ]与arr[ j+1 ]进行交换;

但对于多种类型数据,编写时临时变量不能确定为某一具体类型,

单独封装交换函数Swap以实现交换功能;

2、关于Swap函数的参数类型,由于已强转为char*类型,故其参数类型直接写为char*类型即可;

3、对于Swap函数,仅有待交换元素的起始指针并不能完成交换,还需提供待交换元素大小

void Swap(char* buf1, char* buf2,size_t width) 
{  }

4、由于元素大小未知,可令待交换元素逐字节进行交换,交换元素大小width次

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

2.3 排序函数bubble_sort的实现

void bubble_sort(void* base, // 参数1:泛型指针接收待排序数组基址size_t sz,				 // 参数2:正数变量接收待排数据个数size_t width,            // 参数3:正数变量接收单个待排数据大小int(*cmp)(const void* p1,const void* p2)) {  // 参数4:函数指针变量接收待排数据大小比较函数地址// 确定趟数: // 对于sz个数,需排sz-1趟int i = 0;for (int i = 0; i < sz - 1; i++) {// 1趟排序内:// 假设该序列已经有序:int flag = 1;int j = 0;// 确定1趟内比较次数:// 对于第i趟,待排序数个数:sz-i个,需比较的数的对数:sz-1-i对for (j = 0; j < sz - 1 - i; j++) {// 比较相邻两个数据/元素:if (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0) {// 交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);// 进入循环体发生交换<=>序列非有序,将标志重置为0:flag = 0;}}// 本趟未交换,则表示序列已经有序,终止后续趟数if (flag == 1) {break;}}
}

3. 测试整型数据排序

3.1 整型数据比较函数cmp_int的实现

int cmp_int(const void* p1, const void* p2) {return *(int*)p1 - *(int*)p2;
}

3.2 整型数据排序后输出函数print_int的实现

void print_int(int* arr, int sz) {for (int i = 0; i < sz; i++) {printf("%d ", *(arr + i));}
}

3.3 整型数据测试函数test_int的实现 

void test_int() {int arr[] = { 9,7,5,3,1,8,6,4,2,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);print_int(arr, sz);
}

3.4 完整程序及运行结果 

#include<stdio.h>
int cmp_int(const void* p1, const void* p2) {return *(int*)p1 - *(int*)p2;
}
void Swap(char* buf1, char* buf2,size_t width) {for (int i = 0; i < width; i++) {char* tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
void bubble_sort(void* base, // 参数1:泛型指针接收待排序数组基址size_t sz,				 // 参数2:正数变量接收待排数据个数size_t width,            // 参数3:正数变量接收单个待排数据大小int(*cmp)(const void* p1,const void* p2)) {  // 参数4:函数指针变量接收待排数据大小比较函数地址// 确定趟数: // 对于sz个数,需排sz-1趟int i = 0;for (int i = 0; i < sz - 1; i++) {// 1趟排序内:// 假设该序列已经有序:int flag = 1;int j = 0;// 确定1趟内比较次数:// 对于第i趟,待排序数个数:sz-i个,需比较的数的对数:sz-1-i对for (j = 0; j < sz - 1 - i; j++) {// 比较相邻两个数据/元素:if (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0) {// 交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);// 进入循环体发生交换<=>序列非有序,将标志重置为0:flag = 0;}}// 本趟未交换,则表示序列已经有序,终止后续趟数if (flag == 1) {break;}}
}
void print_int(int* arr, int sz) {for (int i = 0; i < sz; i++) {printf("%d ", *(arr + i));}
}
void test_int() {int arr[] = { 9,7,5,3,1,8,6,4,2,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);print_int(arr, sz);
}
int main() {test_int();return 0;
}

运行结果如下:

4. 测试结构体型数据排序

4.1 创建结构体型数据

typedef struct Stu {char name[20];int age;
}Stu;

4.2 结构体型数据比较函数cmp_stu_byxxxx的实现

由于结构体有多个成员变量,分别编写对应排序函数:

int cmp_stu_byname(const void* p1, const void* p2) {strcmp(((Stu*)p1)->name, ((Stu*)p2)->name);//strcmp( (*((Stu*)p1)).name, (*((Stu*)p1)).name );
}
int cmp_stu_byage(const void* p1, const void* p2) {return ((Stu*)p1)->age - ((Stu*)p2)->age;/*return (*((Stu*)p1)).age - (*((Stu*)p1)).age;*/
}

4.3 结构体型数据排序后输出函数print_stu的实现

void print_stu(Stu* arr, int sz) {for (int i = 0; i < sz; i++) {printf("name:%s, age:%d\n", arr[i].name, arr[i].age);}
}

4.4 结构体型数据测试函数test_stu的实现

void test_stu() {struct Stu arr[3] = { {"zhangsan",20},{"lisi",19},{"wangwu",21} };int sz = sizeof(arr) / sizeof(arr[0]);printf("sorted by name:\n");bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_byname);print_stu(arr, sz);printf("\n");printf("sorted by age:\n");bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_byage);print_stu(arr, sz);
}

4.5 完整程序及运行结果

#include<stdio.h>
#include<string.h>
typedef struct Stu {char name[20];int age;
}Stu;
int cmp_stu_byname(const void* p1, const void* p2) {strcmp(((Stu*)p1)->name, ((Stu*)p2)->name);//strcmp( (*((Stu*)p1)).name, (*((Stu*)p1)).name );
}
int cmp_stu_byage(const void* p1, const void* p2) {return ((Stu*)p1)->age - ((Stu*)p2)->age;/*return (*((Stu*)p1)).age - (*((Stu*)p1)).age;*/
}
void print_stu(Stu* arr, int sz) {for (int i = 0; i < sz; i++) {printf("name:%s, age:%d\n", arr[i].name, arr[i].age);}
}
void test_stu() {struct Stu arr[3] = { {"zhangsan",20},{"lisi",19},{"wangwu",21} };int sz = sizeof(arr) / sizeof(arr[0]);printf("sorted by name:\n");bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_byname);print_stu(arr, sz);printf("\n");printf("sorted by age:\n");bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_byage);print_stu(arr, sz);
}
void bubble_sort(void* base, // 参数1:泛型指针接收待排序数组基址size_t sz,				 // 参数2:正数变量接收待排数据个数size_t width,            // 参数3:正数变量接收单个待排数据大小int(*cmp)(const void* p1,const void* p2)) {  // 参数4:函数指针变量接收待排数据大小比较函数地址// 确定趟数: // 对于sz个数,需排sz-1趟int i = 0;for (int i = 0; i < sz - 1; i++) {// 1趟排序内:// 假设该序列已经有序:int flag = 1;int j = 0;// 确定1趟内比较次数:// 对于第i趟,待排序数个数:sz-i个,需比较的数的对数:sz-1-i对for (j = 0; j < sz - 1 - i; j++) {// 比较相邻两个数据/元素:if (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0) {// 交换两个元素Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);// 进入循环体发生交换<=>序列非有序,将标志重置为0:flag = 0;}}// 本趟未交换,则表示序列已经有序,终止后续趟数if (flag == 1) {break;}}
}
int main() {test_stu();return 0;
}

运行结果如下:

相关文章:

【C语言】_使用冒泡排序模拟实现qsort函数

目录 1. 排序函数的参数 2. 排序函数函数体 2.1 比较元素的表示 2.2 交换函数Swap的实现 2.3 排序函数bubble_sort的实现 3. 测试整型数据排序 3.1 整型数据比较函数cmp_int的实现 3.2 整型数据排序后输出函数print_int的实现 3.3 整型数据测试函数test_int的实现 3…...

openCvSharp 计算机视觉图片找茬

一、安装包 <PackageReference Include"OpenCvSharp4" Version"4.10.0.20241108" /> <PackageReference Include"OpenCvSharp4.runtime.win" Version"4.10.0.20241108" /> 二、准备两张图片 三、编写代码 using OpenCv…...

从零开始开发纯血鸿蒙应用之处理外部文件

从零开始开发纯血鸿蒙应用 一、外部文件二、外部文件的访问形式1、主动访问2、被动访问 三、代码实现1、DocumentViewPicker2、Ability Skills3、onNewWant 函数4、冷启动时处理外部文件 一、外部文件 对于移动端app来说&#xff0c;什么是外部文件呢&#xff1f;是那些存储在…...

Spring中三级缓存详细讲解

1、Spring三级缓存是什么&#xff0c;过程是怎么样的&#xff1f; Spring 中的三级缓存主要用于单例 Bean 的生命周期管理&#xff0c;特别是在循环依赖时&#xff0c;它通过不同阶段暴露 Bean 实例来确保依赖注入的顺利完成。缓存的内容如下&#xff1a; 一级缓存 (singleton…...

论文阅读:《Whole-animal connectomes of both Caenorhabditis elegans sexes》

一 论文整体概述 论文下载链接&#xff1a;《Whole-animal connectomes of both Caenorhabditis elegans sexes》 补充信息和额外数据&#xff1a;https://www.nature.com/articles/s41586-019-1352-7 1. 作者期刊背景 该论文由Scott W. Emmons&#xff0c;David H. Hall等…...

嵌入式开发之STM32学习笔记day03

STM32之ADC&#xff08;模拟数字转换器&#xff09; 1 ADC简述2 ADC转换时间3 ADC转化结果存放机制4 ADC转化结果存放机制5 ADC电压转换 1 ADC简述 ADC&#xff08;Analog-Digital Converter&#xff09;模拟—数字转换器&#xff1b;ADC可以将引脚上连续变化的模拟电压转换为…...

windows10 安装 Golang 版本控制工具g与使用

下载包&#xff1a;https://github.com/voidint/g/releases 解压&#xff0c; 并添加到环境变量 g 常用命令 查询当前可供安装的stable状态及所有的 go 版本 # stable 版本 g ls-remote stable# 所有版本 g ls-remote安装目标 go 版本1.23.4g install 1.23.4切换到已安装的…...

SpringBoot 使用 Cache 集成 Redis做缓存保姆教程

1. 项目背景 Spring Cache是Spring框架提供的一个缓存抽象层&#xff0c;它简化了缓存的使用和管理。Spring Cache默认使用服务器内存&#xff0c;并无法控制缓存时长&#xff0c;查找缓存中的数据比较麻烦。 因此Spring Cache支持将缓存数据集成到各种缓存中间件中。本文已常…...

R数据分析:多分类问题预测模型的ROC做法及解释

有同学做了个多分类的预测模型,结局有三个类别,做的模型包括多分类逻辑回归、随机森林和决策树,多分类逻辑回归是用ROC曲线并报告AUC作为模型评估的,后面两种模型报告了混淆矩阵,审稿人就提出要统一模型评估指标。那么肯定是统一成ROC了,刚好借这个机会给大家讲讲ROC在多…...

数据结构与算法之二叉树: LeetCode 654. 最大二叉树 (Ts版)

最大二叉树 https://leetcode.cn/problems/maximum-binary-tree/ 描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值递归地在最大值 左边 的 子数组前缀上 构建左子树递归地在最大值…...

Linux 容器漏洞

定义&#xff1a;Linux 容器漏洞是指在容器技术&#xff08;如 Docker、LXC 等&#xff09;运行环境中存在的安全弱点。这些漏洞可能存在于容器镜像本身、容器运行时&#xff08;如 runc&#xff09;、容器编排工具&#xff08;如 Kubernetes&#xff09;或者容器与主机之间的交…...

file与io流(1)

-1- java.io.File类的使用 &#xff08;1&#xff09; 概述 File类及本章下的各种流&#xff0c;都定义在java.io包下。一个File对象代表硬盘或网络中可能存在的一个文件或者文件目录&#xff08;俗称文件夹&#xff09;&#xff0c;与平台无关。&#xff08;体会万事万物皆…...

忘记了PDF文件的密码,怎么办?

PDF文件可以加密&#xff0c;大家都不陌生&#xff0c;并且大家应该也都知道PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密&#xff1f; PDF和offi…...

Linux权限管理(用户和权限之间的关系)

Linux系列 文章目录 Linux系列一、Linux下用户类型二、普通权限的基本概念2.1、Linux中权限的类别2.2、Linux中权限对应的三种身份2.3、文件权限的标识 三、文件权限设置四、修改文件属主和属组4.1、chown修改文件的属主4.2、修改所属组 五、文件掩码六、目录权限 一、Linux下用…...

Python Selenium库入门使用,图文详细。附网页爬虫、web自动化操作等实战操作。

文章目录 前言1 创建conda环境安装Selenium库2 浏览器驱动下载&#xff08;以Chrome和Edge为例&#xff09;3 基础使用&#xff08;以Chrome为例演示&#xff09;3.1 与浏览器相关的操作3.1.1 打开/关闭浏览器3.1.2 访问指定域名的网页3.1.3 控制浏览器的窗口大小3.1.4 前进/后…...

【Uniapp-Vue3】使用defineExpose暴露子组件的属性及方法

如果我们想要让父组件访问到子组件中的变量和方法&#xff0c;就需要使用defineExpose暴露&#xff1a; defineExpose({ 变量 }) 子组件配置 父组件配置 父组件要通过onMounted获取到子组件的DOM 传递多个属性和方法 子组件 父组件...

【多模态LLM】英伟达NVLM多模态大模型训练细节和数据集

前期笔者介绍了OCR-free的多模态大模型&#xff0c;可以参考&#xff1a;【多模态&文档智能】OCR-free感知多模态大模型技术链路及训练数据细节&#xff0c;其更偏向于训练模型对于密集文本的感知能力。本文看一看英伟达出品的多模态大模型NVLM-1.0系列&#xff0c;虽然暂未…...

HTTP详解——HTTP基础

HTTP 基本概念 HTTP 是超文本传输协议 (HyperText Transfer Protocol) 超文本传输协议(HyperText Transfer Protocol) HTTP 是一个在计算机世界里专门在 两点 之间 传输 文字、图片、音视频等 超文本 数据的 约定和规范 1. 协议 约定和规范 2. 传输 两点之间传输&#xf…...

MySQL教程之:输入查询

如上一节所述&#xff0c;确保您已连接到服务器。这样做本身不会选择任何要使用的数据库&#xff0c;但没关系。在这一点上&#xff0c;了解一下如何发出查询比直接创建表、加载数据和从中检索数据更重要。本节介绍输入查询的基本原则&#xff0c;使用几个查询&#xff0c;您可…...

docker+ffmpeg+nginx+rtmp 拉取摄像机视频

1、构造程序容器镜像 app.py import subprocess import json import time import multiprocessing import socketdef check_rtmp_server(host, port, timeout5):try:with socket.create_connection((host, port), timeout):print(f"RTMP server at {host}:{port} is avai…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...

【见合八方平面波导外腔激光器专题系列】用于干涉光纤传感的低噪声平面波导外腔激光器2

----翻译自Mazin Alalus等人的文章 摘要 1550 nm DWDM 平面波导外腔激光器具有低相位/频率噪声、窄线宽和低 RIN 等特点。该腔体包括一个半导体增益芯片和一个带布拉格光栅的平面光波电路波导&#xff0c;采用 14 引脚蝶形封装。这种平面波导外腔激光器设计用于在振动和恶劣的…...

C++ 变量和基本类型

1、变量的声明和定义 1.1、变量声明规定了变量的类型和名字。定义初次之外&#xff0c;还申请存储空间&#xff0c;也可能会为变量赋一个初始值。 如果想声明一个变量而非定义它&#xff0c;就在变量名前添加关键字extern&#xff0c;而且不要显式地初始化变量&#xff1a; e…...

无人机避障——感知部分(Ubuntu 20.04 复现Vins Fusion跑数据集)胎教级教程

硬件环境&#xff1a;NVIDIA Jeston Orin nx 系统&#xff1a;Ubuntu 20.04 任务&#xff1a;跑通 EuRoC MAV Dataset 数据集 展示结果&#xff1a; 编译Vins Fusion 创建工作空间vins_ws # 创建目录结构 mkdir -p ~/vins_ws/srccd ~/vins_ws/src# 初始化工作空间&#xf…...

gorm 配置数据库

介绍 GORM 是 Go 语言中最流行的 ORM&#xff08;对象关系映射&#xff09;库之一&#xff0c;基于数据库操作的封装&#xff0c;提供类似 Django ORM / SQLAlchemy 的开发体验。 特性描述支持多种数据库MySQL、PostgreSQL、SQLite、SQL Server、ClickHouse 等自动迁移自动根…...

基于开源AI大模型AI智能名片S2B2C商城小程序源码的中等平台型社交电商运营模式研究

摘要&#xff1a;本文聚焦中等平台型社交电商&#xff0c;探讨其与传统微商及大型社交电商平台的差异&#xff0c;尤其关注产品品类管理对代理运营的影响。通过引入开源AI大模型、AI智能名片与S2B2C商城小程序源码技术&#xff0c;构建智能化运营体系。研究结果表明&#xff0c…...