【C进阶】qsort函数使用及模拟实现

当字节在指尖跳动时,你是否能谱写这青春的赞歌

在这里插入图片描述

大家好,初次见面,请多关照🙈🙉🙊。在本篇博客中,新一将会为大家介绍qsort函数使用及其模拟。(以下结果均在VS2022中编译)希望在方便自己复习的同时也能帮助到大家。😜😜😜🥇🥈🥉

废话不多说,直接进入我们的文章。



一.🥇 温故而知新:冒泡排序

1.1🥈 升序——冒泡

我们先来实现一下我们熟悉的冒泡排序函数😎😎😎

冒泡排序: 冒泡排序是众多排序算法中的一种,其余排序算法还有快速排序希尔排序选择排序插入排序 等等,在后续的学习中新一会带大家把基本的排序算法都遍历一遍,敬请期待🙈🙉🙊,我们先用一张动图来了解我们的冒泡排序算法
在这里插入图片描述
这是其中的一趟排序,总结下来就是让大数沉底

1.2🥈 冒泡代码实现

根据上述分析,我们知道要想实现整个数组的排序,就必须多趟排序,多趟比较 🧐🧐🧐

void bubble_sort(int arr[], int sz)//传入arr数组,以及元素个数
{
	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;
			}
		}
	}
}

值得注意的是,每趟排序沉底的元素后续不需要比较即每趟冒泡排序次数依次递减,此时我们再引入main函数看看实现效果。

void print(int arr[], int sz)//打印函数
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
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 test_bubble()//将其封装在一个函数内,方便后续修改main函数
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//冒泡排序
	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);
	print(arr, sz);
}
int main()
{
	test_bubble();
	return 0;
}

在这里插入图片描述
但是我们试想,我们自己实现的这个冒泡排序函数,能不能排序浮点型,结构体,字符型数据?,显然是不行的,这样的话我们使用起来就会造成一定的麻烦。

二.🥇 步入正题:qsort函数

2.1🥈 qsort函数介绍

qsort函数: qsort函数是基于快速排序算法实现的一个排序的函数,它的牛逼之处在于能一键排序多种类型的数据,不再拘泥于排序一种类型的数据,我们先来看看它的参数类型

在这里插入图片描述
这是个查找函数的网站,用起来十分方便快捷,推荐大家使用,网站我会放在评论区

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

头文件#include<stdib.h>
第一个参数void* base指目标数组的首元素地址
第二个参数size_t num指目标数组的元素个数
第三个参数size_t size指目标数组的元素的大小(占几个字节)
第四个参数int (* compar)(const void*,const void*)这是需要操作者自己定义的一个函数,该函数第一个和第二个参数类型都是void*类型,由此实现多种数据类型的排序

🚀第四个参数返回类型是int类型,我们通过对上述图片的了解(最下面)知道了对于数组中任意两个元素:a b
a < b:返回值-1
a = b:返回值0
a > b:返回值1

注意a > b返回值只要为正即可,a < b时返回值为负即可

2.2🥈 qsort函数实现

2.21🥉排序整形

我们先来搭建好qsort函数的框架。

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

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

	qsort(arr, sz, sizeof(arr[0]), cmp_int);//依据上述介绍的参数类型
	print(arr, sz);
}
int main()
{
	test_qsort_int();
	return 0;
}

现在最重要的就是实现自己定义的cmp_int函数其参数void*类型,表示空指针类型,我们可以通过强转来改变其数据类型,所以这个函数直接决定了我们所排序的数据类型 下面是新一写的cmp_int函数🤔🤔🤔

int cmp_int(const void* e1, const void* e2)
{
	//void* 类型不能直接解引用,因为不确定访问几个字节
	if (*(int*)e1 > *(int*)e2)//由于排序整形数据。强转为int*类型
	{
		return 1;
	}
	else if (*(int*)e1 == *(int*)e2)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

这样会不会太麻烦呢?用if语句判断代码量太多,既然我们可以根据返回值的正负来判断大小,我们不妨直接相减

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

这样就很巧妙的实现了cmp_int函数,结果读者可以自行验证哦。🙈🙉🙊

2.22🥉排序结构体

有了上一种类型的思想,相信实现结构体的排序对大家来说也不是难事。

struct Stu
{
	char name[20];
	int age;
	double score;
};
int cmp_stu_by_age(const void* e1, const void* e2)//根据年龄对结构体排序
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;//强转为所定义的结构体指针类型
}
int cmp_stu_by_name(const void* e1, const void* e2)//根据名字对结构体排序
{
	return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name);
}
void test_qsort_Stu()
{
	struct Stu arr[3] = { {"zhangsan", 30, 55.5},{"lisi", 20, 88},{"wangwu", 50, 90.0} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);//验证年龄
}
int main()
{
	test_qsort_Stu();
	return 0;
}

这里我们以调试的方式验证年龄

这是之前未排序数据
在这里插入图片描述

这是排序后数据
在这里插入图片描述
排序成功

三.🥇 主体升华:bubble_sort函数改造

3.1🥈 整体框架

这里我们用改造的bubble函数来排序结构体

struct Stu
{
	char name[20];
	int age;
	double score;
};
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name);
}

void test_bubblesortpro_Stu()
{
	struct Stu arr[3] = { {"zhangsan", 30, 55.5},{"lisi", 20, 88},{"wangwu", 50, 90.0} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort_pro(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}
//主函数
int main()
{
	test_bubblesortpro_Stu();
	return 0;
}

3.2🥈 关键函数实现

其余函数实现都跟前面一样。那么现在主要工作就是 实现bubble_sort_pro(arr, sz, sizeof(arr[0]), cmp_stu_by_name)

void bubble_sort_pro(void* base, int num, int width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//if (arr[j] > arr[j + 1])//比较
			if (cmp((char*)base + width * j, (char*)base + width * (j + 1)) > 0)
			{
				//交换
				Swap((char*)base + width * j, (char*)base + width * (j + 1), width);
			}
		}
	}
}

我们依照冒泡排序*的框架来构建我们改造后的函数这里我们主要改造比较部分和交换部分

3.21🥉比较部分

由于我们需要考虑各种类型的数据所以得让我们的比较具有普遍性,我们知道最小的数据类型的char型,那么我们不妨用char来当做我们的底层,在一个字节的基础上加上每个数据的大小width * j,即代表了每个元素之间的互相比较

🚀举个例子
对于数组int arr[5] = { 1,2,3,4,5 }, 假设首元素地址为1,占四个字节,第二个元素地址为5,占四个字节,当我们的 j 为0时,即表示比较地址1 +sizeof(int) * j地址 1 + sizeof(int) * (j + 1)类型,即第一个和第二个元素的比较

3.22🥉交换部分

我们要想实现各种数据类型的交换,必须还是以char为框架,以参数的形式传入width即数据元素大小实现交换

void Swap(char* pa, char* pb, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)//逐字节交换
	{
		int temp = *pa;
		*pa = *pb;
		*pb = temp;
		pa++;
		pb++;
	}
}

3.3🥈 结果验证

我们继续以调试的方式来验证

交换前
在这里插入图片描述
交换后
在这里插入图片描述
我们的结果得到了验证.

想对大家说的话

家人们,学到这里我们已经彻底学会了使用qsort函数以及其模拟实现🥳🥳🥳后续新一会持续更新C语言进阶的有关内容,学习永无止境,技术宅,拯救世界!
在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Corwttaml

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值