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

不同音频振幅dBFS计算方法

1. 振幅的基本概念 振幅是描述音频信号强度的一个重要参数。它通常表示为信号的幅度值&#xff0c;幅度越大&#xff0c;声音听起来就越响。为了更好地理解和处理音频信号&#xff0c;通常会将振幅转换为分贝&#xff08;dB&#xff09;单位。分贝是一个对数单位&#xff0c;能…...

【17. 电话号码的字母组合 中等】

题目&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits “23”…...

数据结构初阶---排序

一、排序相关概念与运用 1.排序相关概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的…...

【从0-1实现一个前端脚手架】

目录 介绍为什么需要脚手架&#xff1f;一个脚手架应该具备哪些功能&#xff1f; 脚手架实现初始化项目相关依赖实现脚手架 发布 介绍 为什么需要脚手架&#xff1f; 脚手架本质就是一个工具&#xff0c;作用是能够让使用者专注于写代码&#xff0c;它可以让我们只用一个命令…...

AI文章管理系统(自动生成图文分发到分站)

最近帮一个网上的朋友做了一套AI文章生成系统。他的需求是这样&#xff1a; 1、做一个服务端转接百度文心一言的生成文章的API接口。 2、服务端能注册用户&#xff0c;用户在服务端注册充值后可以获取一个令牌&#xff0c;这个令牌填写到客户端&#xff0c;客户端就可以根据客…...

【Leetcode 每日一题】3270. 求出数字答案

问题背景 给你三个 正 整数 n u m 1 num_1 num1​&#xff0c; n u m 2 num_2 num2​ 和 n u m 3 num_3 num3​。 数字 n u m 1 num_1 num1​&#xff0c; n u m 2 num_2 num2​ 和 n u m 3 num_3 num3​ 的数字答案 k e y key key 是一个四位数&#xff0c;定义如下&…...

基于单片机的无线气象仪系统设计(论文+源码)

1系统方案设计 如图2.1所示为无线气象仪系统设计框架。系统设计采用STM32单片机作为主控制器&#xff0c;结合DHT11温湿度传感器、光敏传感器、BMP180气压传感器、PR-3000-FS-N01风速传感器实现气象环境的温度、湿度、光照、气压、风速等环境数据的检测&#xff0c;并通过OLED1…...

【数据库】Mysql精简回顾复习

一、概念 数据库&#xff08;DB&#xff09;&#xff1a;数据存储的仓库数据库管理系统&#xff08;DBMS&#xff09;&#xff1a;操纵和管理数据库的大型软件SQL&#xff1a;操作关系型数据库的编程语言&#xff0c;是一套标准关系型数据库&#xff08;RDBMS&#xff09;&…...

深入理解 HTTP 的 GET、POST 方法与 Request 和 Response

HTTP 协议是构建 Web 应用的基石&#xff0c;GET 和 POST 是其中最常用的请求方法。无论是前端开发、后端开发&#xff0c;还是接口测试&#xff0c;对它们的深入理解都显得尤为重要。在本文中&#xff0c;我们将介绍 GET 和 POST 方法&#xff0c;以及 Request 和 Response 的…...

MySQL 中联合索引相比单索引性能提升在哪?

首先我们要清楚所以也是要占用磁盘空间的&#xff0c;随着表中数据量越来越多&#xff0c;索引的空间也是随之提升的&#xff0c;因而单表不建议定义过多的索引&#xff0c;所以使用联合索引可以在一定程度上可以减少索引的空间占用其次&#xff0c;使用联合索引的情况下&#…...

国企网站建设合同/深圳网站设计公司

文章目录一.原型链机制1. 原型链的本质2. 引用类型的构造函数3. 基本类型的包装类二. 对象与属性1. 对象直接打点验证某个属性是否存在4. instanceof 运算符三. 继承1. 原型链继承2. 构造函数继承3. 组合继承一.原型链机制 1. 原型链的本质 只要是对象&#xff0c;一定有原型…...

深圳网站建设 公司元/金华网站推广

position: absolute;text-overflow:ellipsis;word-wrap:break-word...

北京网站设计公司兴田德润怎么样/百度推广点击一次多少钱

1.安装插件&#xff1a; 这里可以搜索到插件并安装。 2.修改快捷键或查找快捷键&#xff1a; 这里可以进行快捷键的查找和修改 3.进入引用文件&#xff1a; 点击f12&#xff0c;或者右击快捷键可以看到进入引用文件的快捷方法。 4.查看目录&#xff1a; 转载于:https://www.cnb…...

网站的百度推广怎么做/公关服务

参考&#xff1a;https://blog.csdn.net/zl544434558/article/details/47857343 在一个eclipse启动多个tomcat&#xff0c;修改tomcat的端口是不可以的&#xff0c;需要修改tomcat的shutdown端口、tomcat访问端口、jvm启动端口 修改步骤&#xff1a; 1 双击tomcat server 在每个…...

河北省和城乡建设厅网站/求职seo推荐

此块内容参考Ajax文档部分。主要复习内容&#xff1a;1.JavaScript核心对象 2.浏览器BOM对象3.文档对象模型DOM4.常见事件5.Ajax编程(web交互2种方式的对比)6.传统Ajax编程的步骤以及从服务器端返回的数据格式 7.JSON数据格式的转换操作 8.jQuery选择器 9.jQuery的Ajax编程(常见…...

德阳住房和城乡建设厅网站/qq群推广方法

IOS的逆向签名方法 1.将.ipa文件解压->Payload->右击.app文件&#xff0c;显示包内容->找到embedded.mobileprovision文件->将其拷贝出来&#xff0c;以便后面使用2.若没有安装homebrew,ruby,sign,则先依次安装3.homebrew的安装方式&#xff1a;curl -LsSf http://…...