详解qsort函数的使用及模拟实现qsort函数

news2025/1/23 10:34:48

目录

引言:

1. qsort函数简介:

🎈qsort函数原型:

 🎈函数参数介绍:

🎈比较函数(compar)的编写:

🎈(补充) void*类型的指针:

2.qsort函数示例: 

2.1对int类型排序:

2.2对char类型排序: 

2.3对浮点型排序: 

2.4对结构体类型进行排序: 

3. 模拟实现qsort函数:

结语: 


引言:

qsort函数是C语言中的一个非常有用的库函数,底层使用的是快速排序的方式,用于对数据进行排序。对数据进行排序的方法有很多,例如:冒泡排序、选择排序、插入排序等,快速排序只是这众多排序方法中的一种。这个函数可以直接使用,并且可以用来排序任意类型的数据。本文将详细介绍qsort函数的使用方法,并模拟实现一个简单的qsort函数。

1. qsort函数简介:

在学习库函数的过程中,遇到陌生的函数,我们可以通过cplusplus网站来了解它。

🎈qsort函数原型:

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

 🎈函数参数介绍:

🎈比较函数(compar)的编写:

比较函数是qsort函数的一个重要参数,它定义了排序的规则。比较函数应满足以下条件:

qsort函数compar函数规定了特定的参数,所以我们设计cmp函数时要严格遵守其参数设定。需要注意的是:函数的返回结果一定要确保是整型,如果不是一定要强制类型转换成整型。 

💘整型数据的比较 :

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

💘浮点型数据的比较: 

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

💘字符串大小的比较: 

int cmp_str_size(const void* e1, const void* e2)
{
	return strcmp((char*)e1, (char*)e2);
}

💘字符串长度的比较:

int cmp_str_len(const void* e1, const void* e2)
{
	return strlen((char*)e1) - strlen((char*)e2);
}

💘结构体变量的比较: 

int cmp_by_name(const void* e1, const void* e2)
{
	return (int)(((stu*)e1)->age - ((str*)e2)->age);
}

🎈(补充) void*类型的指针:

对于int*的指针+1跳过一个整型,解引用访问4个字节char*的指针+1跳过1个字节,解引用访问1个字节。但是对于void*的指针既不能进行解引用操作,也不能进行加减整数的操作,它是一个无具体类型的指针,就像一个“垃圾桶”一样,可以用来存放任意类型数据的地址,使用的时候,只需进行强制类型转换即可。

2.qsort函数示例: 

2.1对int类型排序:

💘升序情况:

#include <stdio.h>
#include <stdlib.h>//使用qsort函数需要包含头文件

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

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

	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

运行结果: 

💘降序情况: 

#include <stdio.h>
#include <stdlib.h>//使用qsort函数需要包含头文件

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

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

	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

运行结果:

2.2对char类型排序: 

#include <stdio.h>
#include <stdlib.h>//使用qsort函数需要包含头文件

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

int main()
{
	char arr[] = { 'b','e','f','c','a','d' };
	int sz = sizeof(arr) / sizeof(arr[0]);

	qsort(arr, sz, sizeof(arr[0]), cmp_char);
	for (int i = 0; i < sz; i++)
	{
		printf("%c ", arr[i]);
	}

	return 0;
}

运行结果:

2.3对浮点型排序: 

💘注意:

在使用qsort函数浮点型进行排序时,需要使用三目运算符(条件运算符)来定义比较函数的返回值。这是因为浮点数存在精度问题,直接使用减法运算符来比较两个浮点数可能会导致不准确的结果。在比较函数中,返回值为负数表示第一个元素小于第二个元素,返回值为表示两个元素相等,返回值为正数表示第一个元素大于第二个元素。

#include <stdio.h>
#include <stdlib.h>//使用qsort函数需要包含头文件

int cmp_float(const void* e1, const void* e2)
{
	return ((*(float*)e1) > (*(float*)e2) ? 1 : -1);
}

int main()
{
	float arr[] = { 1.2, 5.6, 8.7, 3.4, 9.0 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	qsort(arr, sz, sizeof(arr[0]), cmp_float);
	for (int i = 0; i < sz; i++)
	{
		printf("%.1f ", arr[i]);
	}

	return 0;
}

运行结果:

2.4对结构体类型进行排序: 


#include <stdio.h>
#include <stdlib.h>//使用qsort函数需要包含头文件
#include <string.h>

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

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

int main()
{
	struct stu arr[3] = { {"zhangsan", 20}, {"lisi", 18}, {"wangwu", 36} };
	int sz = sizeof(arr) / sizeof(arr[0]);

	qsort(arr, sz, sizeof(arr[0]), cmp_age);
	for (int i = 0; i < sz; i++)
	{
		printf("%s %d ", arr[i].name, arr[i].age);
	}

	return 0;
}

运行结果:

3. 模拟实现qsort函数:

💘我们今天模拟实现的qsort函数是在冒泡排序的基础上而实现的,那我们先来看一下冒泡排序的实现。

 💘冒泡排序的原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个,这个数就会从序列的最右边冒出来。以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。

#include <stdio.h>

void Buttle_Sort(int arr[], int sz)
{
	//共进行sz-1趟
	for (int i = 0; i < sz - 1; i++)
	{
		//每一趟
		for (int 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;
			}
		}
	}
}

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

	Buttle_Sort(arr, sz);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

 💘下面我们要做的就是改造冒泡排序,使之成为可以排序任意类型的数组的函数,以整型数组为例:

#include<stdio.h>
void swap(char* p1, char* p2, int width) 
{
	for (int i = 0; i < width; i++) //不知道是什么类型,所以要一个字节一个字节来进行交换
	{
		char temp = *p1;
		*p1 = *p2;
		*p2 = temp;
		p1++;
		p2++;
	}
}

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


//void* base - 要求排序不同类型的数组,void*恰好能接收任意类型的数据
//int num - 元素个数
//int width - 一个元素的大小
//int (*compare)(const void* p1, const void* p2)  函数传参函数指针接收
int bubble_qsort(void* base, int num, int width,int (*compare)(const void* p1, const void* p2))) 
{
	for (int i = 0; i < num - 1; i++) 
	{
		for (int j = 0; j < num - 1 - i; j++) 
		{
			//强制类型转化为char*型的数据,是因为一开始不知道数组的类型
            //如果要访问数据的话,只能一个字节一个字节的访问
			//这样有利于排序各种类型的数   	
			if (compare((char*)base + j * width,(char*)base + (j + 1) * width) > 0) 
			{
				//写一个Swap函数来交换
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}


}

int print(int arr[], int num)
{
	for (int i = 0; i < num; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main() 
{
	int arr[10] = { 5,7,9,1,3,4,6,8,2,0 };
	int num = sizeof(arr) / sizeof(arr[0]);//计算数组中的元素个数

    //打印排序前的数组
    printf("排序前为:");
    print(arr, num);
	printf("\n");

	bubble_qsort(arr, num, sizeof(arr[0]), compare);

	//打印排序后的数组
    printf("排序后为:");
	print(arr, num);

	return 0;
}

运行结果:

在上面的程序中,我们首先定义了一个swap函数,用于交换两个元素的值。然后,我们定义了一个bubble_qsort函数来实现冒泡排序算法。在bubble_qsort函数中,我们使用两个嵌套的循环来遍历数组,并调用compare函数比较相邻的元素。如果比较函数返回的结果大于0,说明当前元素需要交换位置,我们就调用swap函数来实现交换。通过多次遍历和交换,我们可以将数组中的元素按照指定的比较规则进行排序。在main函数中,我们定义了一个待排序的整型数组,并调用bubble_qsort函数来对其进行排序。最后,我们打印排序后的数组,输出结果为:0 1 2 3 4 5 6 7 8 9,即为排序后的数组。

结语: 

本文详细介绍了qsort函数的使用方法,并模拟实现了一个简单的qsort函数。通过使用qsort函数,我们可以方便地对各种类型的数组进行排序。如果觉得本篇文章对大家有所帮助,不妨一键三连支持一下博主,蟹蟹!

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

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

相关文章

java将excel中用例写到world中【搬代码】

首先创建用例 例如&#xff1a; 运行代码: 预期结果&#xff1a; 实际结果&#xff1a;与预期结果不符合&#xff0c;哪位大佬有代码传授一下啊&#xff0c;实在是不知道咋写了 代码&#xff1a; package com.znzdh.qitagongju; import com.spire.doc.*; import com.spire…

安徽省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著

安徽省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著

InstallShield打包升级时不覆盖原有文件的解决方案

一个.NET Framework的Devexpress UI Windows Form项目&#xff0c;用的InstallShield&#xff0c;前些个版本都好好的&#xff0c;最近几个版本突然就没法更新了&#xff0c;每次更新的时候都覆盖不了原文件&#xff0c;而且这样更新后第一次打开程序&#xff08;虽然是老程序&…

ReID网络:MGN网络(5): 一点延伸: 缩减特征维度, 提高匹配效率

1. MGN网络输出 在实际使用MGN时&#xff0c;是将网络尾部的特征进行导出&#xff0c;并进行相关的相似性度量。 如图1所示&#xff0c;MGN特网络在析出特征的结尾处执行了concat操作。如果每一条特征维度是256的话&#xff0c;那么MGN最终输出将是2048维的特征。 图1 MGN特征…

香港汇丰银行开户

作为香港较知名的银行之一&#xff0c;汇丰银行提供了丰富的金融服务&#xff0c;包括个人银行服务、企业银行服务以及国际银行服务等。对于需要在香港开展业务或投资的人来说&#xff0c;开立一个汇丰银行账户是必不可少的。那么&#xff0c;开立汇丰银行账户需要哪些资料&…

医院用泛微构建数字化信创平台,人财物、医教研、文事会统一管理

近年来&#xff0c;国家多次发布政策&#xff0c;驱动医疗行业的智慧化转型。医疗行业作为重点领域&#xff0c;正在大力推进信创发展&#xff0c;数字化和信创将共同助力医院的高质量发展。 国家卫健委发布的《医院智慧管理分级评估标准体系&#xff08;试行&#xff09;》、…

【算法训练-数组 五】【二分查找】:旋转排序数组的最小数字、旋转排序数组的指定数字

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【数组的二分查找】&#xff0c;使用【数组】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为…

fast-lio2添加wheel在发散时轨迹约束

fast-lio2主要算法为迭代误差卡尔曼滤波算法&#xff0c;imu作为预测&#xff0c;点云更新&#xff0c;当点云发散时输出位姿异常&#xff0c;漂移很大&#xff0c;后端在融合出现崩溃情况&#xff0c;加入轮速计约束发散时位姿。 1.订阅wheel话题 2.发散检测&#xff0c;检测…

mybatisplus配置拦截器实现保存加密,输出解密,模糊查询

前言&#xff1a;因公司需求需要把某些实体类的某些字段值进行加密保存&#xff0c;在查询时解密明文输出。现记录两种方式。 一、第一种方式&#xff1a; &#xff08;1&#xff09;使用TableField(typeHandler TypeHandler.class)注解自带的字段类型处理器&#xff0c;写一…

盲盒游戏开发方案

盲盒游戏是一种新兴的游戏类型&#xff0c;其核心机制是让玩家在购买时不知道会获得哪一种物品&#xff0c;从而产生一种探索的乐趣。那么&#xff0c;如何开发一个盲盒游戏呢&#xff1f;以下是一些步骤和要点。 一、确定游戏目标和规则 在开发盲盒游戏时&#xff0c;…

前端:nodejs多版本管理工具nvm

nvm是什么 nvm全英文也叫node.js version management&#xff0c;是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具&#xff0c;为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js。 nvm下载 可在点此在github上下载最新版本,本次…

拷贝构造函数(深拷贝+浅拷贝)

目录 拷贝构造函数浅拷贝深拷贝 拷贝构造函数 拷贝构造函数&#xff1a; Myclass(const Myclass& myclass) {amyclass.a;bmyclass.b;cmyclass.c; }浅拷贝 浅拷贝的思路就是和默认的拷贝构造函数一样: 即将原对象的值直接赋值给新对象&#xff0c;这样做一般情况下是没什…

加拿大儿童床垫认证标准要求介绍SOR/2016-152

儿童床垫是专为儿童设计的睡眠配件&#xff0c;用于提供舒适的睡眠环境和正确的睡眠支持 SOR/2016-152是加拿大政府发布的法规&#xff0c;旨在确保儿童床垫的安全性和质量。SOR/2016-152标准要求儿童床垫具有足够的安全性能&#xff0c;能够保护儿童免受潜在的危险和伤害。 标…

ArcGIS10.1软件安装教程

ArcGIS10.1中英文&#xff08;32/64位)下载地址&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/1Ksm112WaKMMk6La9ircCng 密码&#xff1a;t70f 安装步骤&#xff1a; 1、我们对安装包进行解压&#xff0c;直接鼠标右击解压即可。 2、 打开我们解压的文件夹&#…

瞄准办公场景,未来智能靠“AI+耳机”后来居上?

如何在广阔红海中开拓出蓝海&#xff1f;未来智能或可作为参考案例。 作为TWS耳机玩家&#xff0c;未来智能成立于2021年&#xff0c;日前完成了由天际资本领投的数千万元Pre-A轮融资&#xff0c;这也是该公司成立以来完成的第二轮融资。 从成立时间来看&#xff0c;在广阔的…

Python学习之路 01如何安装Python

&#x1f600;前言 在当今数字化的时代&#xff0c;编程已成为一项基本技能。Python&#xff0c;因其简洁易学、功能强大和高度可扩展性而闻名&#xff0c;已成为许多初学者和专业开发人员的首选编程语言。不仅如此&#xff0c;Python拥有一个庞大而活跃的社群&#xff0c;提供…

科学中的人工智能:量子、原子和连续体技术概述

人工智能&#xff08;AI&#xff09;的进步正在推动自然科学领域的一种新的发现范式。如今&#xff0c;AI已经开始通过改进、加速和促进我们对各种空间和时间尺度上自然现象的理解来推动自然科学的发展&#xff0c;催生了一个被称为AI for science&#xff08;AI4Science&#…

SpringMVC之JSON数据返回及异常处理机制

目录 一.JSON数据的返回 二.异常处理机制 2.1 异常处理方式一 2.2 异常处理方式二 2.3 异常处理方式三 一.JSON数据的返回 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;常用于Web应用程序和服务之间的数据传输。通过使用…

MATLAB R2022b遇到“License Manager Error -8”怎么解决

电脑系统更新过后&#xff0c;matlab突然用不了了&#xff0c;报Error -8错误 将破解文件中的 libmwlmgrimpl.dll 复制 粘贴到 安装目录/R2022b/bin/win64/matlab_startup_plugins/lmgrimpl 直接替换 然后直接在 安装目录/R2022b/bin/ 打开matlab.exe

mingw 编译 curl ,Qt 工程使用

mingw 编译 curl 下载curl 源码 https://github.com/curl/curl 我使用8.3版 CMake-gui 配置 源码路径&#xff1a;D:/workspace/CPP/curl-8.3.0 生成路径: D:/workspace/CPP/curl-8.3.0/mingw-build 点击 Configure ,弹窗配置&#xff0c;选择 MinGW Makefiles 选择 Spec…