C语言——利用冒泡排序模拟实现qsort函数

news2024/12/23 16:21:10

一.冒泡排序

冒泡排序是C语言中众多排序中的一种。它的排序逻辑为(升序):从第一个元素开始和相邻的比较,如果第一个元素大于第二个元素,则交换,反之不交换;第二个再与第三个元素比较,第二个大于第三个交换,反之不交换……一趟之后,最大的元素将会出现在数组的最后一个;下来再重头开始,继续比较。

我们可以看到,一趟交换,就会将最大的元素放在数组的最后,我们在进行下一趟交换,就可以把次大值放在数组倒数第二个位置。这就是冒泡排序的基本逻辑,下来我们用代码来实现:

//冒泡排序
void bubble_sort(int* nums, int numsSize)
{
	//趟数
	int i = 0;
	for (i = 0; i < numsSize - 1; i++)
	{
		//每一趟需要交换的次数
		int j = 0;
		for (j = 0; j < numsSize - i - 1; j++)
		{
			//前一个大于后一个就进行交换
			if (nums[j] > nums[j + 1])
			{
				int tmp = nums[j + 1];
				nums[j + 1] = nums[j];
				nums[j] = tmp;
			}
		}
	}
}

二.qsort函数

我在上一期博客已经详细的介绍了qsort函数,我们现在来复习一下qsort函数的功能、参数及返回值。

qsort函数的功能就是快速排序一任意类型数组。

而它的参数分别为:待排序数组,数组的大小,数组中每个元素的大小,比较函数。

qsort函数无返回值。

我们知道了qsort函数的功能及参数后,我们就可以在上面写的冒泡排序函数上进行修改,以此达到模拟qsort函数的功能。

三.模拟qsort函数

首先我们是依据冒泡排排序来进行模拟的,而qsort函数本来使用的快速排序。本质上都是排序,我们可以知道,冒泡排序的趟数和每趟交换的次数是不用进行修改的。修改的有:比较两相邻元素的大小、两元素的交换、以及函数参数。

1.函数参数的修改

既然要模仿qsort函数,所以我们应该保持函数参数的一致。

//nums 待排序数组
//numsSize 待排序数组的大小
//width 数组中每个元素的大小
//int(*compare)(const void*, const void*) 比较函数

void bubble_sort(void* nums, size_t numsSize, size_t width, int(*compare)(const void*, const void*))
{

}

2.修改两相邻元素之间的比较方式

因为qsort函数可以比较任意类型的数组,所以传递数组的类型为void*型。而在上一期博客我已经介绍到,两元素之间的比较应该由该函数的使用者来编写,因为使用者肯定知道他们排序的是什么类型的数组。所以,之前冒泡排序中的if语句中的判断条件就应该修改为比较函数对两相邻元素的比较的返回值。比较函数的返回值为整型,>0交换  =0不交换 <0也不交换(默认排序后为升序)。

//比较函数
if (compare((char*)nums + j * width, (char*)nums + (j + 1) * width))
{

}

我们可以先将待比较的两个元素强制转换为char*类型,但是这样的话就会改变原来元素的类型
所以我们再给强转之后的结果乘上数组每个元素的大小即width,这样每个指针访问的时候访问的都是原来数组类型的字节个数
例如:待排序数组为int型,转为char*后,如果直接传给比较函数,就会造成数据的截断,因为整型每个元素占四个字节
我们给其乘上width之后,就相当于指针向后走了width个位置,就相当于指向了下一个整型的位置。
但我们知道,比较的时候,要一直往后走进行比较,所以我们可以给width乘上一个j变量,j = 0,相当与第一个整型,j = 1,相当于跳过了一个width的长度,即一个整型,j = 2的时候,相当于跳过了两个整型。所以,这样就可以比较任意类型的两元素。

3.两元素的交换

之前的冒泡排序只能交换整型,而我们想交换其他类型的时候往往不适用,所以我们可以将元素的交换抽象成一个函数,利用该函数对元素进行交换。

void Swap(char* p1, char* p2, size_t width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char c = *p1;
		*p1 = *p2;
		*p2 = c;
		p1++;
		p2++;
	}
}

假设我们交换的是整型数据,但传过来的却是字符型,这怎么交换呢?

这幅图就是Swap函数交换的逻辑。我们可以一个字节一个字节的进行交换,因为我们将每个元素的大小传给了Swap函数,所以可以据此利用循环的方式,将其每一个字节都进行交换。

四.利用模拟函数进行整型数据的排序

综合上面的内容,我们就可以写出以冒泡排序为基础的qsort函数的模拟函数。

void bubble_sort(void* nums, size_t numsSize, size_t width, int(*compare)(const void*, const void*))
{
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		int j = 0;
		for (j = 0; j < numsSize - 1 - i; j++)
		{
			
			if (compare((char*)nums + j * width, (char*)nums + (j + 1) * width) > 0)
			{
				Swap((char*)nums + j * width, (char*)nums + (j + 1) * width, width);

			}

		}
	}
}

我们现在利用此函数,进行整型数组的排序:

#include <stdio.h>

//比较函数
int compare_int(const char* p1, const char* p2)
{
	return *(int*)p1 - *(int*)p2;
}

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

//模拟函数
void bubble_sort(void* nums, size_t numsSize, size_t width, int(*compare)(const void*, const void*))
{
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		int j = 0;
		for (j = 0; j < numsSize - 1 - i; j++)
		{
			
			if (compare((char*)nums + j * width, (char*)nums + (j + 1) * width) > 0)
			{
				Swap((char*)nums + j * width, (char*)nums + (j + 1) * width, width);

			}

		}
	}
}


//打印函数
void Print(int* nums, int numsSize)
{
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		printf("%d ", nums[i]);
	}
}

void test()
{
	int nums[] = { 10,9,8,7,6,5,4,3,2,1 };
	int numsSize = sizeof(nums) / sizeof(nums[0]);
	bubble_sort(nums, numsSize,sizeof(nums[0]),compare_int);
	Print(nums, numsSize);
}

int main()
{

	//模拟qsort函数
	test();
}

结果为:

五.结语

到此,利用冒泡排序模拟qsort函数已经完成,要想排序不同的类型只需改变比较函数即可(上期博客已介绍,故不在此赘述)。

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

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

相关文章

jsvmp逆向实战X-Bogus篇,算法还原

jsvmp逆向实战X-Bogus篇&#xff0c;算法还原 前言X-Bogus算法逻辑寻找log插桩位置第四步第三步 前言 看过很多大佬关于X-Bogus算法还原的文章&#xff0c;都是通过log插桩&#xff0c;分析日志信息再结合动态调试一步步抽丝剥茧&#xff0c;最终还原算法&#xff0c;但是不同…

第1篇:Mysql数据库表结构导出字段到Excel(一个sheet中)

package com.xx.util;import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.sql.*; import java.io.*;public class DatabaseToExcel {public static void main(String[] args) throws Exception {// 数据库连接配置String u…

基于SpringBoot和HeatMap的全球地震热力图可视化实践

目录 前言 一、关于热力图 1、HeatMap简介 2、属性和方法介绍 二、全球地震热力图反演 1、地震信息查询开发 2、前端地图开发 三、地震带反演成果 1、三大地震带反演 2、地震区域分析 总结 前言 众所周知&#xff0c;全球的地震带主要可以分为三处地震带——环太平洋地…

利用API打造卓越的用户体验

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 正文 1. 数据驱动的设计 2. 功能扩展与整合 3. 实时性与响应性 4. 个性化推荐与定制化服务 结语 我的其他博客 正文 随着数字化时代的…

我的电脑win11系统安装了谷歌浏览器,桌面的快捷方式打不开

安装好浏览器以后双击打不开右键打开文件位置也弹窗报错提示 但是我发现开始栏里面可以打开 说明我的软件应该是没有问题的&#xff0c;研究了一下 我实际的安装目录在&#xff1a;C:\Program Files\Google\Chrome\Application 桌面的快捷方式右键查看属性显示的地址却不对&a…

js生成笛卡尔集合

let arr[[黑, 金, 白],[16G, 32G],[电信, 移动, 联通], ]let listarr.reduce((a, b) > { return a.flatMap(x > b.map(y > [...x, y]))}, [[]] )console.log(list)生成结果

easyExcel大数据量导出oom

easyExcel大数据量导出 异常信息 com.alibaba.excel.exception.ExcelGenerateException: java.lang.OutOfMemoryError: GC overhead limit exceededat com.alibaba.excel.write.ExcelBuilderImpl.fill(ExcelBuilderImpl.java:84)at com.alibaba.excel.ExcelWriter.fill(Excel…

(MATLAB)第二十一章 Simulink仿真设计初步

Simulink是MATLAB的重要组成部分&#xff0c;可以非常容易地实现可视化建模&#xff0c;并把理论研究和工程实践有机地结合在一起&#xff0c;不需要书写大量程序&#xff0c;只需要使用鼠标和键盘对已有模块进行简单的操作和设置。 21.1 Simulink简介 Simulink是MATLAB软件的…

汽车ECU的虚拟化技术(五) -- 对MCU虚拟化实现难点的思考

目录 1.概述 2.虚拟化软件的难点 2.1 虚拟化中的中断处理 2.2 虚拟ECU的通信 3.小结 1.概述 在上面文章里汽车ECU的虚拟化技术(四) -- 对MCU虚拟化实现难点的思考-CSDN博客&#xff0c;解了OEM面临新的电子电气架构下的集成难点&#xff0c;引入了hypervisor以及VM调度机制…

内网使用rustdesk进行远程协助

文章目录 前言一、搭建rustdesk中继服务器二、搭建文件下载服务器三、创建引导脚本四、使用 前言 内网没有互联网环境&#xff0c;没法使用互联网上有中继服务器的远程协助工具&#xff0c;如teamviewer、todesk、向日癸等&#xff1b;在内网进行远程维护可以自己搭建中继服务…

缤纷浏览器 —— 一键换肤,个性随心换(H5实现浏览器换肤效果)

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

新版仿蓝奏网盘|城通网盘|百度网盘|闪客网盘|网盘源码系统,个人网盘系统

(购买本专栏可免费下载栏目内所有资源不受限制,持续发布中,需要注意的是,本专栏为批量下载专用,并无法保证某款源码或者插件绝对可用,介意不要购买!购买本专栏住如有什么源码需要,可向博主私信,第二天即可发布!博主有几万资源) 这是一款仿蓝奏网盘、城通网盘、百…

BGP4+简介

定义 BGP是一种用于自治系统AS&#xff08;Autonomous System&#xff09;之间的动态路由协议&#xff0c;常用版本是BGP-4&#xff0c;BGP-4只能传递IPv4路由。针对IPv6的BGP4扩展&#xff0c;通常称为BGP4。 目的 BGP4用于在AS之间传递路由信息&#xff0c;并不是所有情况…

自媒体用ChatGPT批量洗稿软件V5.9环境配置/软件设置教程【汇总】

大家好&#xff0c;我是淘小白~ 首先&#xff0c;感谢大家的支持~~ ChatGPT采集洗稿软件V5.9版本更新&#xff0c;此次版本更新修改增加了一些内容&#xff1a; 1、自定义多条指令&#xff0c;软件自动判断指令条数&#xff0c;进行输入 2、增加谷歌浏览多账号轮询&#xf…

Orbit 使用指南 07 | 创建强化学习环境 | Isaac Sim | Omniverse |

如是我闻 在谈论了如何创建基础环境后&#xff0c;我们现在将探索如何为强化学习创建任务环境。 基础环境被设计为一个感知-行动环境&#xff08;sense-act environment&#xff09;&#xff0c;代理&#xff08;agent&#xff09;可以向环境发送命令并从环境接收观测。这种最…

Meta 推出SceneScript,一种全新的3D场景重建方式

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

高项-案例分析练习(范围管理)

案例一 公司在2014年初承接了一个医疗信息系统项目&#xff0c;要求2014年底完成该项目研发任务并进行试运行&#xff0c;2015年负责项目全年的运行维护&#xff0c;运行稳定后甲方验收合格项目才能结束。由于张工具有多年的医疗系统开发管理经验&#xff0c;公司领导任命他为项…

用BSP优化3D渲染

3D渲染引擎设计者面临的最大问题之一是可见性计算&#xff1a;只必须绘制可见的墙壁和物体&#xff0c;并且必须以正确的顺序绘制它们&#xff08;应该在远处的墙壁前面绘制近墙&#xff09; 。 更重要的是&#xff0c;对于游戏等应用程序来说&#xff0c;开发能够快速渲染场景…

Flutter动画(一)Ticker、Animate 原理

在任何系统的UI框架中&#xff0c;动画原理都是类似的&#xff0c;即&#xff1a;在一段时间内&#xff0c;快速地多次改变UI外观&#xff1b;由于人眼会产生视觉暂留&#xff0c;所以最终看到的就是一个“连续”的动画。 Flutter中对动画进行了抽象&#xff0c;主要涉及 Anim…

2.6、媒体查询(mediaquery)

概述 媒体查询作为响应式设计的核心,在移动设备上应用十分广泛。媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。媒体查询常用于下面两种场景: 针对设备和应用的属性信息(比如显示区域、深浅色、分辨率),设计出相匹配的布局。当屏幕发生动态改变时(比如分屏…