排序之玩转qsort函数——【C语言】

这篇具有很好参考价值的文章主要介绍了排序之玩转qsort函数——【C语言】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

说起排序,我们会想起许多算法,在之前的博客中我也写到过,比如:冒泡排序法、快速排序法、选择排序法等等。其实在C语言中一直有一个可以将数组中的内容进行排序的函数且功能完善内容齐全的库函数——qsort函数。今天就让我们来探索一下吧!


目录

回调函数

初始qsort函数

如何创建比较函数

qsort函数的引用

模拟qsort函数


回调函数

在了解qsort函数时,我们先来说一下什么时回调函数。

回调函数:

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当 这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调 用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

回调函数其实是对某一类函数的一种称呼,在使用时我更感觉类似一种嵌套关系,在对应的时间使用回调函数就会有意想不到的收获。

在使用qsort函数时我们会用到回调函数,所以qsort函数可以在更广泛的常见进行运用(整型、浮点型、字符串、结构体等等)。接下来就让我们走进qsort函数中!


初始qsort函数

qsort库函数是在#include<stdlib.h>中的,作用就是对数组中的元素进行排序。

qsort函数的特点:

1.使用的是快速排序的方法

2.适合于任何类型数据的排序

排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言 以上就是qsort函数的返回值与各个参数的内容,现在我们进行分析:

返回值:void(不返回任何内容)

参数:

void* base:指向要排序的数组的第一个对象的指针,转换为 void *

size_t num:数组中由base指向的元素数。 size_t是无符号整型。

size_t size:数组中每个元素的大小(以字节为单位)size_t是无符号整型。

int (*compar) (const void*, const void*):这是一个函数指针,实参应该给其一个函数的地址,其中给予的函数的返回值为int,两个参数是指向比较两个元素的函数的指针。

排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言

 

所以在使用qsort函数时,我们应该创建一个比较的函数传入qsort函数中让其使用。 创建的比较函数应该与自己想要比较的数组内容进行匹配,对应不同的数组内容,我们应该创建不同的比较函数进行比较。


如何创建比较函数

在创建自己想要比较的compar函数时,最重要的一点时遵循qsort参数的模板进行创建,否则qsort函数将无法使用。

void*(空指针):它可以接收任何类型的指针变量,但是不能进行指针操作,因为它没用空间访问权限,如果没有注意此情况编译器就会报错。所以我们在给予赋值时必须将它强制类型转换,转换为自己需要的数据类型即可。

当排序数组为整型数组:

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

排序数组为字符串数组时,我们应该使用#include<string.h>中的strcmp函数进行比较:

int compar(const void* p1, const void* p2)
{
	return (strcmp(*(char*)p1 , *(char*)p2));
}

 结构体数组时,比较内容为字符串时:

int compar(const void* p1, const void* p2)
{
	return strcmp((struct stu*)p1->name , (struct stu*)p2->name);
}

 以上是几个比较典型的例子,看完这些例子我相信已经知道compar函数应该怎么创建了,下面让我们来上一段代码进行实操。


qsort函数的引用

根据上面的说明,我们基本已经掌握qsort函数的基本使用方法,现在让我们通过代码对qsort函数有更进一步的认识。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

struct Stu
{
	char name[20];
	int age;
};
void print(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

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

int compar2(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}


void test1()
{
	int arr1[10] = { 3,1,5,2,9,7,4,8,0,6 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	qsort(arr1, sz, sizeof(arr1[0]), compar1);
	print(arr1, sz);
}

void test2()
{
	struct Stu arr2[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu",16} };
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	qsort(arr2, sz, sizeof(arr2[0]), compar2);
	for (int i = 0; i < sz; i++)
	{
		printf("\n%s %d", arr2[i].name, arr2[i].age);
	}
}
int main(void)
 {
	test1();
	test2();
	return 0;
}

这段代码是将一个整数数组和结构体数组中的字符串进行升序排序。这里我想说一下字符之间的比大小是通过它们的ASCII码值进行比较。运行结果如下:排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言 如果想要进行降序排序,我们只需要将compar函数中的比较的两个值进行交换即可。排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言

排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言


模拟qsort函数

根据我们在使用qsort函数的一些功能特点,来模拟出qsort函数的功能。

qsort函数的功能就是排序,所以这个函数中一定有某种排序的方法,在这里我们将使用冒泡排序法进行。(其他排序方法也是可以的)

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;
			}
		}
	}
}

这是一个最标准的冒泡排序法,我们通过上面的排序代码为框架进行模拟qsort函数。

假设就使用这个函数当作qsort函数,我们就会发现很多问题!!!

问题一:参数只能接收整型数组,其他数组不能被接收。

解决:我们就可以模仿qsort函数中的第一个参数,将第一个参数改为void* base,这样什么类型的数组我们都可以接收。

问题二:当我们使用void*base作为第一个参数时,指针的移动应该怎么实现?(数组元素的大小和数量)

解决:继续仿照qsort函数,加入size_t num和size_t size.

问题三:上述函数中两数两两比较是建立于整数基础上的比较,所以使用> < >= <=就可以实现。如果传入的数组为结构体数组时,我们就不能用比较整数的比较方法实现了。(对于不同类型的数据不能简单的使用>进行比较)

解决:我们就需要用到回调函数,将两个元素的比较方法,以函数参数的形式传递。(函数指针将成为第四个参数) 

当创建好compar函数时,我们应该怎么去给compar函数去传递参数呢?

compar函数是多个函数,通过不同的调用我们可以比较不同的数组,但是在模拟函数中给compar函数传参的位置只有一个,我们应该考虑兼顾所以的数组类型。

我们知道了数组中每个元素的大小,相当于我们知道其元素在内存中所占的大小,为了兼顾所有数据,我们用访问内存权限最小的指针char*来作为基本单位,在乘上每个元素的大小,就可以实现任何数据的访问。

排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言 在for循环中使用即可访问数组中的所有元素。

当传入的元素在compar函数中比较如果大于0,就要进行元素内容交换。又有问题出现了,传入的数据类型不同,交换的内容大小不同,为了其中的兼容性,我们可以继续沿用上述思想,创建一个swap交换函数,传入刚才compar函数使用的两个函数地址和数组一个元素所占内存大小size即可。排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言

swap函数会将两个数据中的数据一个字节一个字节的交换,这也可以保证所有类型数组都可以进行。 

所有的准备工作已经完成,下面让我们完成qsort函数的模拟。

#include<stdio.h>
#include<string.h>
void print(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

void swap(char*p1,char*p2,int size)
{
	int i = 0;
	char tmp = 0;
	for (i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}


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

void bubble_sort(void* base, int num, int size, int (*cmp)(const void*, const void*))
{
	int i = 0; 
	for (i = 0; i < num-1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}

void test1()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), compar);
	print(arr, sz);
}



int main(void)
{
	test1();
}

如果想加入其他类型数组进行排序,只需要加入新的compar函数和要比较的内容即可,如果想要降序排序,只需将if函数中>0改为<0即可。下面是成功运行的结果: 

排序之玩转qsort函数——【C语言】,c语言,数据结构,开发语言

模拟的qsort函数主体为bubble_sort函数和swap函数:

void bubble_sort(void* base, int num, int size, int (*cmp)(const void*, const void*))
{
	int i = 0; 
	for (i = 0; i < num-1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}

void swap(char*p1,char*p2,int size)
{
	int i = 0;
	char tmp = 0;
	for (i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}

 文章来源地址https://www.toymoban.com/news/detail-543722.html

到了这里,关于排序之玩转qsort函数——【C语言】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言 快速排序——qsort函数详解

            我们在使用冒泡排序法做题的时候,经常会遇到运算次数过多程序超时的情况,而且冒泡排序法只能对整形数组进行排序。         为了解决这些问题!就使用 qsort函数 吧! 目录 一、qsort函数使用方法 二、qsort函数使用示例      1.数组排序      2.字符数组排序  

    2024年02月03日
    浏览(50)
  • 【C语言】qsort()函数详解:能给万物排序的神奇函数

    🦄 个人主页 :修修修也 🎏 所属专栏 :C语言 ⚙️ 操作环境 : Visual Studio 2022   目录 一.qsort()函数的基本信息及功能 二.常见的排序算法及冒泡排序 三.逐一解读qsort()函数的参数及其原理 1.void* base 2.size_t num 3.size_t size 4.int (*compar)(const void*,const void*) 四.使用qsort()函数完成整形,

    2024年02月06日
    浏览(48)
  • C语言题目 - 调用qsort函数对数组进行排序

    如题 其实没什么难的,只要严格按照 qsort 函数的参数来填充即可,这里要用到 函数指针 。 qsort 函数的原型如下: void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void *)); 参数说明: base :指向需要排序的数组的指针,数组中每个元素的大小应为 size 字节。

    2024年02月11日
    浏览(45)
  • 【C语言】——指针六:冒泡排序与qsort函数的实现

    1.1、冒泡排序的原理      在实践过程中,我们难免会碰到要给一组数据排序的情况。如果我们掌握一些排序的算法,效率就会高很多。排序的方法有方法有很多,如:希尔排序,快速排序,堆排序……,今天,我们讲的排序方法就是—— 冒泡排序 !      冒泡排序

    2024年04月16日
    浏览(50)
  • 【C语言】回调函数,qsort排序函数的使用和自己实现,超详解

    先记录一下访问量突破2000啦,谢谢大家支持!!! 这里是上期指针进阶链接,方便大家查看:添加链接描述 大家好呀,今天分享一下上期指针进阶中剩余的内容——回调函数,这个很重要滴,让我们一起来学会学懂他吧!!! 标准概念: 回调函数就是一个通过函数指针调

    2024年02月12日
    浏览(53)
  • 玩转堆排序以及Topk问题——【数据结构】

    W...Y的主页 😊 代码仓库分享  💕 目录 堆排序  建堆  建堆的时间复杂度 Topk问题 学习了二叉树以及堆,今天我们来学习一下什么是堆排序以及经典二叉树问题——topk问题。 在学习开始我们先来回顾一下上篇博客中我们提到的堆,在实现堆时我们要进行向上调整或向下调

    2024年02月07日
    浏览(39)
  • 【数据结构】带你玩转排序:堆排序、希尔排序、插入排序、选择排序、冒泡排序、快排(多版本)、归并排序

    英杰社区 https://bbs.csdn.net/topics/617804998 目录 常见算法的实现         插入排序         希尔排序         堆排序         选择排序         冒泡排序         快速排序         Hoare版本         随机选Keyi               三数取中         挖坑法  

    2024年02月08日
    浏览(56)
  • 冒泡排序模拟实现qsort()函数

    要模拟qsort()函数,我们首先要知道qsort()函数的特点: 使用快速排序的方法。 适用于任何数据类型的排序。 但由于部分学者还没有学习快速排序算法,所以本篇博客采用冒泡排序来模拟功能类似于qsort()的函数bubble_sort。 C库对qsort()函数解释: 我们得到的关于qsort()函数参

    2024年02月16日
    浏览(55)
  • 用冒泡排序实现快速排序(qsort函数),指针进阶实例

    目录   1、qsort函数是什么 2、冒泡排序实现指针进阶 2.1 主函数 2.2 功能函数声明​编辑 2.3 my_qsort函数介绍 2.4 Swap函数 总结           qsort函数是c语言自带的函数,其功能是实现快速排序。我们来看一下他的参数和返回值:         以上就是qsort的参数和返回值,可以看到,

    2024年02月21日
    浏览(44)
  • 对任意类型数都可以排序的函数:qsort函数

    之前我们学习过冒泡排序: 可以看出这样的排序方法只适用于整形类型的数 那么是否有一种排序可以满足所有类型都适用的排序呢? qsort函数排序 应用: 在这里需要补充一下void* 类型的指针 当然qsort函数排序既然可以实现任意类型,那么我们换几个类型试一下; 结构体类

    2024年02月14日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包