【qsort函数实现】

news2025/1/12 7:01:22

前言:
首先在进行讲解之前,我们先进行对函数的一些相关介绍,方便大家更好的理解它。

目录

  • 函数介绍
  • 函数实现

函数介绍

第一步:
我们可以先查询知道函数的使用方法:

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

使用qsort()函数的好处就是可以排序任意类型的数据,不像冒泡排序只能排序整形数组;
此函数使用的排序算法通过调用指定的函数来比较元素对,并将指向它们的指针作为参数;
可以看到这个函数有四个参数:
第一个参数指向要排序的数组的第一个对象的指针,转换为 .void*;
第二个参数是数组中元素的个数;
第三个是数组中每个元素的大小(以字节为单位),是无符号整型。size_t;
第四个指向比较两个元素的函数的指针。

具体可以参见:
https://legacy.cplusplus.com/reference/cstdlib/qsort/?kw=qsort

函数实现

第二步:
使用qsort函数对int类型进行排序:

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}

//测试qsort函数排序整型数据
void test()
{
	int arr[] = { 2,1,3,7,5,9,6,8,0,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr, sz);
}

可以看到我们要比较两个整形元素的大小关系,所以我们设计函数cmp_int()函数,指向比较两个元素的函数的指针。
重复调用此函数以比较两个元素。它应遵循以下原型:qsort

int compar (const void* p1, const void* p2);

将两个指针作为参数(都转换为常量 void*)。该函数通过返回(以稳定和传递的方式)来定义元素的顺序:
在这里插入图片描述
使用qsort函数对结构体类型进行排序:

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

int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
	//字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值
}

int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

//测试qsort排序结构体数据
void test()
{
	struct Stu s[] = { {"张三", 30}, {"李四", 40}, {"王五", 50} };
	int sz = sizeof(s) / sizeof(s[0]);
	//按照名字比较
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	//'按照年龄比较
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}

在这里我们按照结构体中的名字和年龄来排序,我们设计函数 cmp_stu_by_name和cmp_stu_by_age来进行实现,首先通过强制类型转化e1,e2为结构体指针,这里要将(S*)e1先用括号括起来,因为箭头的优先级更高。

到此,qsort函数如何实现的我们清楚了,那么我们可以怎么使用呢?接下来我们通过改造冒泡排序把冒泡排序改为可以比较任何类型排序,即用冒泡排序的思想模拟qsort。

首先我们先来实现冒牌函数:

//bubble_sort 函数只能排序整型数据
void bubble_sort(int arr[], int sz)
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j < sz-1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1]; 
				arr[j + 1] = tmp;
			}
		}
	}
}
void print(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void test1()
{
	//冒泡排序
	//对整型数据进行排序 - 排序为升序
	int arr[] = { 2,1,3,7,5,9,6,8,0,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	print(arr, sz);
}

我们想要改造,首先就是对我们参数的进行改变,变得一致,函数体中的比较部分我们也提出,相邻的个自比较改造如下:
函数参数部分:

void bubble_sort2(void* base, int sz, int width, int (*cmp)(const void* e1, const void*e2))

比较部分:

if (cmp((char*)base+j*width, (char*)base+(j+1)*width)>0)
//交换
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);

cmp的参数是这两个元素的地址,之后在自己所创作的函数中再去强制类型转化为所需类型,第一个元素地址就是base,如何找到之后的呢,首先将其转化为char的指针,其加即就是原地址越过一个字节的地址,这里就需要到了第三个参数int width,代表所占的字节空间数,可以用sizeof直接计算,第一个元素的地+1width就跳到了第二个元素了,后面同理可得(char)base + width * j ,widthj跳过第j个元素的地址,这就代表了第j+1个元素的地址,(char)base + width * (j + 1)代表j+2个元素的地址 ,这样就可以访问到所有元素了,比较完后,if如果大于0.,交换两个元素,所以我们还需要设计一个交换的函数,即如下:

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

我们将两个元素的地址交给Swap(),char类型来接收,但是char只能访问一个字节,接下来我们就需要引入Swap的第三个参数了,width,交换width个字节,及实现了相应的功能。

最后代码如下:

void bubble_sort2(void* base, int sz, int width, int (*cmp)(const void* e1, const void*e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		int j = 0;
		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);
			}
		}
	}
}

到此,qsort函数的介绍便结束了,希望大家多多支持!

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

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

相关文章

二级路由器的设置上网

设置步骤 &#xff08;简单记录一下&#xff09; 前提条件&#xff1a;一级路由器网络正常&#xff0c;这里主要是使用 lan 口&#xff0c;需要确保各个 lan 口正常&#xff0c;我家里是移动公司的路由器&#xff0c;有一个 lan 端口专门给电视用的&#xff0c;选择它来接二级…

ZigBee 3.0实战教程-Silicon Labs EFR32+EmberZnet-5-01:片上资源详解

【源码、文档、软件、硬件、技术交流、技术支持&#xff0c;入口见文末】 【所有相关IDE、SDK和例程源码均可从群文件免费获取&#xff0c;免安装&#xff0c;解压即用】 持续更新中&#xff0c;欢迎关注&#xff01; 前面《ZigBee 3.0实战教程-Silicon Labs EFR32EmberZnet-2…

一个无线鼠标的HID Report Desc

HID设备是USB规范定义的设备类型之一&#xff0c;其分类号为0x03. 关于USB设备类型定义&#xff0c;可参见本站&#xff1a;USB设备类型定义 - USB中文网 HID设备除了用于专门的输入输出设备外&#xff0c;有时也与其它的设备类型组合成一个复杂的设备。如对于UVC摄像头设备&a…

干货!数据智能作为先进生产力,如何助力销售效能提升?

存量竞争市场中&#xff0c;企业需要通过精细化运营提升客户价值与 ROI。数据智能作为先进生产力&#xff0c;在搜索、广告、推荐业务方面已经足够成熟&#xff0c;那么它是如何助力销售提升效能呢&#xff1f;本文将详细介绍。点击文末“阅读原文”即可观看完整版直播回放&…

中科大2007年复试机试题

中科大2007年复试机试题 文章目录中科大2007年复试机试题第一题问题描述解题思路及代码第二题问题描述解题思路及代码第三题问题描述解题思路及代码第四题问题描述解题思路及代码第一题 问题描述 编写程序&#xff0c;判断给定数字是否是回文数。 示例 1 输入&#xff1a;12…

博主的心肝宝贝

写的不错的文档 Sql(Structured Query Language)语句笔记_sky wide的博客-CSDN博客常用sql语句总结https://blog.csdn.net/qq_44652591/article/details/127545318Linux samba服务配置_sky wide的博客-CSDN博客_linux samba配置但是&#xff0c;注意后面公司的需求&#xff0c;…

Docker部署Jenkins

系列文章目录 Docker部署 registry Docker搭建 svn Docker部署 Harbor Docker 部署SQL Server 2017 Docker 安装 MS SqlServer Docker部署 Oracle12c Docker部署Jenkins Docker部署Jenkins系列文章目录前言一、启动docker&#xff0c;下载Jenkins镜像文件二、创建Jenkins挂载目…

fastjson 1.2.24漏洞复现

原理 fastjson由于没有对type进行安全性验证&#xff0c;使攻击者传入危险的类&#xff0c;通过rmi服务指定的攻击机上的恶意class文件&#xff0c;导致命令执行。 版本 1.2.24 环境准备 靶机&#xff1a;ubuntu&#xff0c;192.168.52.129 攻击机&#xff1a;kali&#…

数组的定义和使用

一、一维数组的定义、初始化 1. 一维数组的定义 元素类型 数组名[常量表达式]&#xff1b; &#xff08;1&#xff09;一维数组是由元素类型、数组名和长度组成的构造类型。 &#xff08;2&#xff09;数组名必须符合C标识符规则。 &#xff08;3&#xff09;常量表…

【ONE·C || 初识C语言 】

总言 C语言初步认识。 文章目录总言1、main函数的三种写法2、常见数据类型&#xff1a;内置类型、自定义类型2.1、内置类型总述2.2、内置类型大小计算(32/64)2.3、计算机基本存储单位3、常量、变量3.1、变量3.1.1、变量的分类&#xff1a;全局变量、局部变量3.1.2、变量的作用域…

XL1278-SMT无线模块介绍

XL1278-SMT无线模块简介XL1278-SMT无线模块是采用SEMTECH公司最新的LoRaTM调制技术的无线芯片&#xff0c;该模块除传统的GFSK调制技术外&#xff0c;还采用了LoRa&#xff08;远程&#xff09;扩频技术&#xff0c;具有超远距离扩频通讯&#xff0c;高抗干扰性和最大限度的减小…

SAP 成本组件分割价格详解

本文整理CKM3中“CV成本组件”视图下各项成本的价格取值逻辑。 SELECTTCKH3~ELEMT ”成本构成号TCKH3~EL_HV ”全部成本TCKH1~TXELE ”成本构成名称TKEVA04~WERTKOMP1 ”字段名FROM TCKH3INNER JOIN TCKH1 ON TCKH1~ELEHK TCKH3~ELEHKAND T…

JavaScript 比较 和 逻辑运算符

文章目录JavaScript 比较 和 逻辑运算符比较运算符如何使用逻辑运算符条件运算符JavaScript 比较 和 逻辑运算符 比较和逻辑运算符用于测试 true 或者 false。 比较运算符 比较运算符在逻辑语句中使用&#xff0c;以测定变量或值是否相等。 x5&#xff0c;下面的表格解释了比较…

笔记本电脑连接不上wifi怎么办?看下面4种方法

WIFI可以让我们的网络运行得更快&#xff0c;尤其是对于工作来说&#xff0c;它是不可或缺的。但是有时候&#xff0c;我们明明在笔记本电脑上看到WIFI&#xff0c;但就是连接不上&#xff0c;笔记本电脑连接不上wifi怎么办&#xff1f;方法主要有下面4个&#xff01; 演示机型…

剖析valueOf方法,深入探究Integer缓存实现机制

一. 问题展现我们在面试的时候&#xff0c;面试官经常会给面试者洒出一些迷雾&#xff0c;用来迷惑面试者&#xff0c;这时往往就需要面试者掌握底层源码&#xff0c;才能对问题进行较好的回答。接下来壹哥就以Integer的缓存数组为例&#xff0c;通过分析其源码来教会大家该如何…

Linux串口测试例程

嵌入式Linux开发过程中&#xff0c;进行Linux串口测试&#xff0c;需要针对串口进行回环测试或者指定串口接收一定的数据或者指定串口发送一定的数据使用该测试用例很快验证硬件串口的稳定性和正确性。使用代码连接如下Linux串口测试例程&#xff0c;进行Linux串口测试&#xf…

爬虫逆向之字体反爬(二)、镀金的天空-字体反爬-2

趁热打铁来写字体反爬的第二篇&#xff0c;首先是题目 网页上显示的不是常规的数字&#xff0c;源码里面也是一些汉字 虽然看上去很乱&#xff0c;但是仔细观察还是能发现一些规律&#xff0c;比如&#xff1a;长 对应 2&#xff0c;思对应 1 所以这里的解题思路&#xff0c;也…

基于Python实现四大名著章节标注汉语拼音

起因很单纯&#xff0c;就是给我1年级小豆包的女儿标注三国和西游章节的汉语拼音&#xff0c;我女儿每天都朗读 &#xff0c;结果有很多字不认识&#xff0c;我爱人居然让我给标记不认识的完了手动注音......我勒个去......身为程序员的我怎么能忘记用程序实现呢&#xff0c;特…

再次战胜人类:Meta AI推出首款可以忽悠人的AI模型

文&#xff5c;ShonaCicero&#xff0c;是Meta AI提出的能够在『强权外交』游戏中超越人类的AI模型。它凭借自己"忽悠"人的能力&#xff08;模拟谈判与合作&#xff09;&#xff0c;成为游戏里的顶级高手。AI模型连外交这活儿都能得心应手了&#xff1f;没错&#xf…

【尚硅谷】Java数据结构与算法笔记07 - 排序算法

文章目录一、排序算法简介二、排序的分类三、冒泡排序3.1 基本介绍3.2 算法图解3.3 代码实现四、选择排序4.1 基本介绍4.2 思路分析4.3 算法图解4.4 代码实现五、插入排序5.1 基本介绍5.2 思路分析5.3 算法图解5.4 代码实现六、希尔排序6.1 简单插入排序存在的问题6.2 基本介绍…