好用的库函数,qsort函数大详解(干货满满!)(进阶)

2024-06-17 12:36

本文主要是介绍好用的库函数,qsort函数大详解(干货满满!)(进阶),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

  小编在上一篇文章说了这一篇将要写qsort函数的模拟实现,那么废话不多说,现在开始进入今天的代码之旅喽!


目录:

1.qsort函数的模拟实现的逻辑和思路

2.qsort函数模拟实现的代码实现

3.代码展示


1.qsort函数的模拟实现的逻辑和思路

  读者朋友们是否还记得小编之前说过的一个排序的算法:冒泡排序,今天我们就是用它来模拟实现qsort函数的,如果有读者朋友略微忘记的话,小编先从这里呈现冒泡排序代码的实现来让读者朋友们回忆部分内容:

void my_paopao(int arr[10], int sz)
{int i = 0;int flag = 1;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 tmo = 0;tmo = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmo;flag = 0;}if (flag == 1)break;}}
}
int main()
{int arr[10] = { 0 };int i = 0;for (i = 0; i < 10; i++){scanf("%d", arr + i);}int sz = sizeof(arr) / sizeof(arr[0]);my_paopao(arr, sz);for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

  上面就是冒泡排序代码的实现,如果稍微有点记不清的读者朋友可以看上述代码回忆一下,或者浏览:C语言重要算法之一——冒牌排序详解(干货满满,欢迎各位朋友的观看)-CSDN博客 ,这个是我以前写过的博客,大家可以看这个回顾,回归正题,我们知道,冒泡排序只能排序整型,而qsort函数可以排序任意类型的数组,我们可以以冒泡排序为整体的框架,从而可以模拟qsort函数。

  首先,我们先来回顾一下,qsort函数内部的内容,通过上次小编介绍的网站可以清晰的看到: 

   我们可以先仿照这个来先写一个类似的函数,因为这个是我们自己模拟的,所以可以自己命名,我们对函数描述完以后,就要写函数的主题了,小编前面说过,我们可以保留冒泡排序的框架,所以我们先把代码拿出来来进行思考:

void my_qsortvoid *base,size_t count,size_t width,int (*cop)(const void* p1,const void* p2) )   //这里完全对照qsort函数本身括号内部的内容
{int i = 0;int flag = 1;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 tmo = 0;tmo = arr[j];arr[j] = arr[j + 1];   //当然我们不能这么比较,因为我们有可能设计到字符的比较,对于改进我们在下面叙说,毕竟咱不能一口气吃个小编arr[j + 1] = tmo;flag = 0;}if (flag == 1)break;}}
}

  正如我在上面所说,我们可以把循环给保存好,然后对于内容进行修改,不知道读者朋友们是否还记得小编之前说过qsort是怎么判定可以交换的,如果忘记了请看下图 :

   当返回值大于0的时候将会让两个数进行交换,小于0或者等于0的时候是不发生交换的,那么这个时候,我们就可以我们写的最后一个函数(括号最后一个)指针来进行比较操作,通过此函数的返回值来比较是否大于0,如果大于0再进行交换操作。

  交换操作可以通过我们再写一个交换函数来进行数值的交换,我们在交换的时候,要考虑到我们传参的时候不一定传的就是整型,我们上面式子的交换是只是针对整形的,对于字符型的,小编认为,我们可以通过一个一个字节的来进行交换,这样的话,我们既可以针对字符型,也可以针对整型了,现在我们已经有了这个函数的大致思路了,下面就我们就来进行函数的写正式描写喽!

 

2.qsort函数模拟实现的代码实现

  我们刚开始就要先写一下函数名,通过我们对于qsort函数的了解,下面是代码的实现: 

int arr[10] = { 3,4,5,6,7,8,9,10,1,2 };
int sz = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, sz, sizeof(arr[0]), com_per);  //这里放函数名就好

  之后,我们就要进行比较环节了,循环方面小编就不写了(待会会把完整的代码发出来,大家不要着急),我们首先要靠比较函数来比较大小,对于这方面的实现,我们其实可以完全仿照我们之前运用比较函数的样子,首先我们要先写一个if语句来判定它与0之间的大小关系,下面是代码呈现:

	if (cop((char*)base + j * width, (char*)base + (j+1) * width) > 0){comper((char*)base + j * width, (char*)base + (j + 1) * width, width);   //这是交换的(适用于任何的数)}

  对于函数如何进行比较,小编放在了下图,完全可以仿照我们使用它的时候的比较进行书写(我们这里就以char类型的数据举例): 

 int com_per(const void* p1, const void* p2)
{return ((*(char*)p1) - (*(char*)p2));   //对于字符串的比较才用strcmp
}

  所以说,比较函数我们就原封不动的写就好(此时也是展现了为什么这么比较就可以实现两个数的交换),之后就到了我们这个代码的重头戏,对于我们如何进行两个数的交换,小编在思路部分就说了,我们可以实现一个字节一个字节的交换从而完成所有的交换,所以我们可以直接用char*指针对于我们比较两个数进行接受,然后我们可以写一个循环,通过这个循环来实现每个字节的交换,对于次数的限制,我们就以我们比较数的大小作为最大次数,从而实现字节的交换,我光说可能大家都很疑惑,下面是完整的代码展示:

void comper(char* a1, char* a2,int width)
{int i = 0;char a = 0;for (i = 0; i < width; i++){a = *a1;*a1 = *a2;*a2 = a;a1++;a2++;}
}

  上面便是对于这个交换函数进行的描写,与小编说的一样,此时我们通过循环便可以实现每个数的交换,可能有些读者很疑惑,认为整型是怎么实现交换的,为此小编通过图文的形式进行解释: 

   虽然小编画的有点抽象,但是是这么个道理,这里确实实现了两个数的交换,那么我们通过每次循环,来对于数进行交换了,最终会实现此代码的实现,下面来展示一下这个代码最后的运行图:

   可以很清楚的看已经完成了升序环节,证明此函数模拟成功了,可能现在还有很多读者朋友不知道如何完整的实现这个功能,不要急,小编这就给大家展示源代码!

 

3.代码展示

  小编这里就拿整型和字符型来进行展示了

整型的主函数:

	int arr[10] = { 3,4,5,6,7,8,9,10,1,2 };int sz = sizeof(arr) / sizeof(arr[0]);my_paopao(arr, sz, sizeof(arr[0]), com_per);  //这里放函数名就好int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}

模拟函数(这里通用的,所以下面也不展示了):

void my_paopao(void *base,size_t count,size_t width,int (*cop)(const void* p1,const void* p2))   //这里是模仿的qsort里面的内容来写的
{    //上面也用到了回调函数的思想int i = 0;for (i = 0; i < count - 1; i++)            //这里采用的模板是按照冒泡排序的思想来写的,外在并没被改变,但是内在却和冒泡排序是截然不同的{int j = 0;for (j = 0; j < count - i - 1; j++){if (cop((char*)base + j * width, (char*)base + (j+1) * width) > 0){comper((char*)base + j * width, (char*)base + (j + 1) * width, width);   //这是交换的(适用于任何的数)}}}
}

 比较函数:

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

交换函数(这个是通用的,小编下面就不写了):

void comper(char* a1, char* a2,int width)
{int i = 0;char a = 0;for (i = 0; i < width; i++){a = *a1;*a1 = *a2;*a2 = a;a1++;a2++;}
}

字符型主函数:

	char arr[10] = { 'a','c','d','b','e','h','q','u','x','z' };int sz = sizeof(arr) / sizeof(arr[0]);my_paopao(arr, sz, sizeof(arr[0]), jisuan);int i = 0;for (i = 0; i < sz; i++){printf("%c ", arr[i]);}

比较函数:

 int jisuan(const void* p1, const void* p2)
{return ((*(char*)p1) - (*(char*)p2));   //对于字符串的比较才用strcmp
}

总结;

  小编先声明一下,小编这里是用冒泡排序的方式来模拟实现这个函数的,但不一定代表着只有冒泡排序才可以模拟实现这个函数,对于这个函数的具体实现可能也就只有制作这个函数的人知道了,读者朋友们学会其中的思想就好了,在这里,小编也是连着更了七天的博客了,在这期间我也发现了我忘记了很多知识,果然还是那句话:温故而知新可以为师矣 !大家平常一定要多复习自己学过的知识,避免忘记过多,明天可能会停更一天,小编歇一天,如果文章有错误,恳请大家指出,小编虚心求教,我们下一篇博客见喽!

 

这篇关于好用的库函数,qsort函数大详解(干货满满!)(进阶)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1069459

相关文章

MySQL常用字符串函数示例和场景介绍

《MySQL常用字符串函数示例和场景介绍》MySQL提供了丰富的字符串函数帮助我们高效地对字符串进行处理、转换和分析,本文我将全面且深入地介绍MySQL常用的字符串函数,并结合具体示例和场景,帮你熟练... 目录一、字符串函数概述1.1 字符串函数的作用1.2 字符串函数分类二、字符串长度与统计函数2.1

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Java Thread中join方法使用举例详解

《JavaThread中join方法使用举例详解》JavaThread中join()方法主要是让调用改方法的thread完成run方法里面的东西后,在执行join()方法后面的代码,这篇文章主要介绍... 目录前言1.join()方法的定义和作用2.join()方法的三个重载版本3.join()方法的工作原

Spring AI使用tool Calling和MCP的示例详解

《SpringAI使用toolCalling和MCP的示例详解》SpringAI1.0.0.M6引入ToolCalling与MCP协议,提升AI与工具交互的扩展性与标准化,支持信息检索、行动执行等... 目录深入探索 Spring AI聊天接口示例Function CallingMCPSTDIOSSE结束语