qsort函数详解(C语言排序界的神兵)

简介: qsort函数详解(C语言排序界的神兵)

不管前方的路有多苦,只要走的方向正确,不管多么崎岖不平,都比站在原地更接近幸福


目录


一、qsort函数详解、用法  

二、实现qsort函数

 大家好,我是纪宁。


 这篇文章将为大家带来一个非常厉害的函数,可以迅速解决大家遇到的大部分的排序问题,在没学习数据结构与算法之前,这个函数就是排序界的神!


一、qsort函数详解、用法  

 如果你没有学过数据结构,只会用冒泡排序的话,那么你一定要学习一下qsort快速排序函数。


 qsort函数对使用者来说最舒服的一点是可以排任何数据类型的数据,并且不需用使用者自己写算法来实现排序,下面的截图来自qsort函数的官网(  qsort快速排序函数官网:qsort)




 qsort函数一共有4个参数,第一个参数 base 是要排序集合的首地址;第二个参数 num 是要排序集合的数据的总元素个数;第三个参数 size 是要排序集合每个元素所占内存空间的大小;第四个参数是一个函数指针(int(*)(const void* ,const void*))。其中第四个参数需要使用者自己实现,不过也很简单,只需要判断要比较元素的数据类型,再使用合适的比较数据大小的方法返回一个有符号的整数即可




 因为qsort中的函数指针返回类型为int,两个参数都为 const void*;其次comper函数的作用是实现两个数据类型的比较,所以可以用以下方法设计函数


int Comper(const void* p1, const void* p2)

{

;//需要将传进来的p1、p2进行比较

}

 用p1和p2接受,不过考虑到,p1、p2都为 void*类型的指针,而 void* 类型的指针不能进行解引用,所以在进行比较的时候还要将p1、p2强制类型转化为对应要比较数据的类型的指针,再解引用进行比较,下面举几个不同数据类型的例子


int Comper(const void* p1, const void* p2)

{

return (*(int*)p1) - (*(int*)p2);//整型数据

}

int Comper(const void* p1, const void* p2)

{

return strcmp((*(char*)p1), (*(char*)p2));//字符型数据

}

int Comper(const void* p1, const void* p2)

{

return (*(float*)p1) - (*(float*)p2);//浮点型数据

}

int Cmpper(const void* p1, const void* p2)

{

return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);//结构体类型,成员为整形

}

int Cmpper(const void* p1, const void* p2)

{

return  strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);//结构体类型,成员为字符串

}


 代码中使用qsort函数后,再自己设计一个非常简单的比较函数,编译器就自动将数据排好序了,当然,如果要将数据集合降序排列,只需要将Comper函数中p2与p1的位置交换即可,是不是跃跃欲试,这不比写几十行代码排序简单吗?




二、实现qsort函数

 我们最先接触,使用最多的是 冒泡排序算法,那么我们就用冒泡排序来实现一个完全一样的qsort函数,但在时间复杂度上可能略有不足,大家对冒泡排序的时间复杂度,哈哈,懂的都懂。


 用冒泡排序算法实现qsort函数,冒泡排序的思想是小数冒泡,大数沉淀。但其实有一个最大的问题就是如何做到在冒泡排序的比较部分,实现不同数据类型的比较及交换,对此,我们可以利用它传递过来的参数是空指针这一特点:将空指针强制类型转化为要比较的数据的数据类型的指针,先将转化后的指针解引用来比较大小,再逐字节进行内容交换(在冒泡排序的交换部分再添加一个循环即可)。


void my_qsort(void* base, size_t Num, size_t Size, int(*Com)(const void*, const void*))//首元素地址  元素个数  每个元素的字节数  Com比较函数

{

int i = 0;

for (i = 0; i < Num - 1; i++)//循环的趟数

{

 int j = 0;

 for (j = 0; j < Num - 1 - i; j++)//每趟循环要比较的次数

 {

  //实现比较、交换

  if (Com((char*)base + Size * j, (char*)base + Size * (j + 1)) > 0)

  {

   //交换---逐个字节交换n  

   int z = 0;

   for (z = 0; z < Size; z++)

   {

    char tmp = 0;

    tmp = *((char*)base + Size * j + z);

    *((char*)base + Size * j + z) = *((char*)base + Size * (j + 1) + z);

    *((char*)base + Size * (j + 1) + z) = tmp;

   }

  }

 }

}

}

int Comper(const void* p1, const void* p2)

{

return (*((int*)p1) - *((int*)p2));

}

int main()

{

//测试my_qsort函数

int arr[10] = { 4,3,5,6,7,8,9,10,2,1 };

my_qsort(arr, 10, 4, Comper);

int i = 0;

for (i = 0; i < 10; i++)

{

 printf("%d ", arr[i]);

}

return 0;

}


 比较交换部分实现后,就可以将my_qsort函数当做qsort函数来使用了。




 博主写了好长时间,如果你能给博主一个免费三连鼓励一下博主的话,那么我觉得你的真是 泰     裤    辣 !!!

相关文章
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
68 10
|
1月前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
52 9
|
1月前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
42 8
|
1月前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
52 6
|
1月前
|
存储 C语言
【C语言】输入/输出函数详解
在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
284 6
|
1月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
66 6
|
1月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
43 5
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
61 4
|
2月前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
42 6
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
152 7