当前位置: 首页 > 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…...

随机森林算法在儿童出行方式预测中的实战应用与优化

1. 项目概述&#xff1a;用随机森林预测孩子怎么上学做城市交通规划或者做家长接送方案的时候&#xff0c;你肯定想过一个问题&#xff1a;孩子们到底是怎么上学的&#xff1f;是走路、骑车、坐公交还是家长开车送&#xff1f;这个问题看似简单&#xff0c;背后却牵扯到城市规划…...

Unity iOS构建报错SDK version is 0的根因与精准修复

1. 这个报错不是Unity在“发脾气”&#xff0c;而是工程配置在“装死”刚接手一个老项目&#xff0c;打开Unity编辑器&#xff0c;点Build Settings准备打包iOS&#xff0c;结果弹出一行红字&#xff1a;“SDK version is 0, cannot build”。我第一反应是——这什么鬼&#xf…...

CausalVLR基准测试报告:在IU X-Ray和MIMIC-CXR数据集上的性能分析

CausalVLR基准测试报告&#xff1a;在IU X-Ray和MIMIC-CXR数据集上的性能分析 【免费下载链接】CausalVLR CausalVLR: A Toolbox and Benchmark for Vision-Language Causal Reasoning (多模态因果推理开源框架) 项目地址: https://gitcode.com/gh_mirrors/ca/CausalVLR …...

终极Chrome画中画扩展:如何在浏览器中实现高效视频多任务处理

终极Chrome画中画扩展&#xff1a;如何在浏览器中实现高效视频多任务处理 【免费下载链接】picture-in-picture-chrome-extension 项目地址: https://gitcode.com/gh_mirrors/pi/picture-in-picture-chrome-extension 想要在浏览网页、处理文档的同时继续观看视频内容吗…...

Android Root检测绕过:从逆向分析到Frida分层Hook实战

1. 这不是“绕过root检测”&#xff0c;而是理解检测逻辑后的精准干预在安卓逆向工程的实际工作中&#xff0c;“过root检测”这个说法本身就容易引发误解——它听起来像某种黑箱魔法&#xff0c;仿佛只要套用某个脚本、加载某个插件&#xff0c;就能让App对设备状态“视而不见…...

HiveWE终极指南:快速掌握魔兽争霸III现代化地图编辑器

HiveWE终极指南&#xff1a;快速掌握魔兽争霸III现代化地图编辑器 【免费下载链接】HiveWE A Warcraft III world editor. 项目地址: https://gitcode.com/gh_mirrors/hi/HiveWE 还在为传统魔兽争霸III地图编辑器缓慢的加载速度和复杂的操作界面而烦恼吗&#xff1f;Hiv…...

PS5 NOR Modifier深度解析:如何通过Windows工具修复PS5硬件故障与实现光驱版转数字版

PS5 NOR Modifier深度解析&#xff1a;如何通过Windows工具修复PS5硬件故障与实现光驱版转数字版 【免费下载链接】PS5NorModifier The PS5 Nor Modifier is an easy to use Windows based application to rewrite your PS5 NOR file. This can be useful if your NOR is corru…...

Xia Sql插件:可调试的SQL注入决策引擎

1. 这不是又一个“自动扫SQL”的插件&#xff0c;而是把渗透工程师的判断逻辑塞进了Burp里你有没有过这种经历&#xff1a;在Burp Proxy里看着一堆GET参数、POST JSON、Cookie字段&#xff0c;心里清楚“这里大概率能注入”&#xff0c;但手动拼payload试了七八轮&#xff0c;还…...

Claude Code + LM Studio + CC-Switch 本地自动化编程部署指南

Claude Code LM Studio CC-Switch 本地自动化编程部署指南 本指南汇总了在 Windows 本地环境下&#xff0c;使用 Claude Code 配合 LM Studio 本地模型、CC-Switch 代理进行自动化编程开发的完整配置方案。 目录 硬件与模型选型LM Studio 本地模型部署CC-Switch 代理配置Cla…...

为什么92%的数据库重构失败?Claude设计辅助如何在48小时内规避反范式陷阱?

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;为什么92%的数据库重构失败&#xff1f;——反范式陷阱的本质溯源 数据库重构失败率高达92%&#xff0c;其核心症结并非技术能力不足&#xff0c;而是对“反范式”这一设计策略的误读与滥用。许多团队在性能压…...