【C语言排序利器——qsort函数的介绍,使用,以及伪qsort底层实现】

本文介绍了C++标准库中的qsort函数,通过对比冒泡排序,展示了qsort如何支持不同类型的排序,包括整数、字符串和结构体,并详细讲解了其函数原型、使用方法和比较函数的编写。
摘要由CSDN通过智能技术生成


前言

“我告诉我自己要涂自己喜欢的口红,我告诉我自己要好好生活。”

“我是说,我期待一个春天”


一、qsort函数的介绍

qsort函数是一个用来排序的库函数,底层是用快速排序的思想实现的。

二、引入——由冒泡排序函数引入qsort排序

冒泡排序的思想为:两两相邻元素进行比较,满足顺序就不交换,不满足顺序就交换。
n 个数字要进行n-1趟排序

在这里插入图片描述

代码实现

//冒泡排序(升序版)
#include <stdio.h>

void Print(int* p, int n);
void Bubble_sort(int* p, int n)//排序函数
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < n - 1 - i; j++)
		{
			if (p[j] > p[j + 1])
			{
				int tmp = p[j];
				p[j] = p[j + 1];
				p[j + 1] = tmp;
			}
		}
	}
		Print(p, n);
}

void Print(int* p, int n)//打印函数
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
}

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

代码运行结果展示
在这里插入图片描述
写出来以后,我们仔细观察,就会发现这个函数的性能很差。如图,因为函数参数已经固定,这个函数只能排序整型数组,而qsort函数可以排序任意类型的数据,甚至是字符串以及结构体。那qsort是如何做到的呢?
在这里插入图片描述

三.qsort官网介绍

这是来及cplusplus官网上对于qsort的介绍,链接放在这里,读者可自行阅读 添加链接描述

qsort函数原型如下

头文件
在这里插入图片描述

函数原型在这里插入图片描述
函数参数
在这里插入图片描述

中文注解

//以下为qsort函数原型,以及四个参数的介绍
void qsort (void* base, //void *指针,指向待排序的数组的第一个元素(可理解为基础地址)
            size_t num, //base指向的待排序数组中的元素的个数
            size_t size,//base指向的待排序数组中的元素的大小(以字节为单位)
            int (*compar)(const void*,const void*));//函数指针,指向的为两个函数的比较函数

注意第四个参数,是储存比较函数地址的函数指针。厂家是qsort函数的实现者,我们是qsort函数的使用者,我们明确的知道我们要排序的是什么数据,以及这些数据如何比较,所以,两个函数的比较函数应该由我们提供

这里我们把第四个参数单独拿出来研究。
int (*compar)(const void * ,const void *));,这是一个函数指针
那么传给这个指针地址的函数原型就是
int Compare(const void *a, const void *b)
该函数有两个参数,a与b
a中放的是第一个要比较的元素的地址,b中放的是第二个要比较的元素的地址

这里我们把传给这个指针地址的函数原型拿出来
注意:void* 类型的指针,是无具体类型的指针,不可读不可写入(不可直接解引用),不可加减不可计算。需要强转才可以使用。
如if (* (int*)p1 > * (int*)p2)
在这里插入图片描述

四.qsort函数的使用举例

排序整数的代码实现

//使用qsort函数排序
#include <stdio.h>
#include <stdlib.h>

void Print(int* p, int n)//打印函数
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
}


int Compare(const void* p1, const void* p2)//比较函数的实现
{
	if (*(int*)p1 > *(int*)p2)//void *类型的指针,是无具体类型的指针,不可读不可写入(不可直接解引用),不可加减不可计算
	{
		return 1;
	}
	else if (*(int*)p1 == *(int*)p2)//也可作差,返回差值
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

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

int main(void)
{
	test1();
	return 0;
}

运行结果展示
在这里插入图片描述
结构体排序的代码实现

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

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

int Comparestructname(const void* p1, const void* p2)//按名字排序
{
	return strcmp(((struct stu*)p1)->name , ((struct stu*)p2)->name);
}

int Comparestructage(const void* p1, const void* p2)//按照年龄排序
{
	return (((struct stu*)p1)->age - ((struct stu*)p2)->age);
}

void test2(void)
{
	struct stu arr[3] = { {"xiaotzaozi, 19"}, {"xiaotao", 20}, {"sanxin", 21} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), Comparestructname);
	Print(arr, sz);
}

int main(void)
{
	test2();
	return 0;
}


由于小桃子结构体忘记的差不多了,不太清楚怎么打印结构体数组中的字符串数组,就此做罢了。
从调试可以看出各个变量的变化。

五.改造冒泡排序,让其变成qsort

在冒泡排序的基础上,不改变算法(即仍然使用冒泡排序的思想),实现qsort,而这个函数可以排序任意类型的数据。
我们可以发现,冒泡排序只可以比较整数,那如果要比较字符串以及结构体呢?——那就要更改交换数字的部分。排序对象不一致,排序比较的方法就要更改。
在这里插入图片描述
于是乎,我们就想到把两个元素比较的方法封装成一个函数,然后把函数地址传给排序函数。

重点:排序方法的实现
在这里插入图片描述
代码展示

//使用伪qsort函数——Bubble_sort来排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void Bubble_sort(void* base, size_t sz, size_t width, int (*Compare)(const void* p1, const void* p2));
int Compare(const void* p1, const void* p2);
void Print(int* p, int n);

void Print(int* p, int n)//打印函数
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
}

int Compare(const void* p1, const void* p2)//比较函数的实现
{
	return *(int*)p1 - *(int*)p2;
	//等价于
	//if (*(int*)p1 > *(int*)p2)//void *类型的指针,是无具体类型的指针,不可读不可写入(不可直接解引用),不可加减不可计算
	//{
	//	return 1;
	//}
	//else if (*(int*)p1 == *(int*)p2)
	//{
	//	return 0;
	//}
	//else
	//{
	//	return -1;
	//}
}

void test1()//使用伪qsort函数
{
	int arr[] = { 1,5,3,4,7,6,2,8,9,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Bubble_sort(arr, sz, sizeof(arr[0]), Compare);
	Print(arr, sz);
}

//交换函数,一个一个字节交换
//一大块空间要交换,切成一小块一小块空间去交换
//妙啊
void swap(char* p1, char* p2, size_t n)
{
	for (int i = 0; i < n; i++)
	{
		char tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}

void Bubble_sort(void * base, size_t sz, size_t width, int (* Compare)(const void * p1, const void * p2))//伪qsort函数实现
{
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - 1 - i; j++)
		{
			//比较
			/*if (p[j] > p[j + 1])
			{
				int tmp = p[j];
				p[j] = p[j + 1];
				p[j + 1] = tmp;
			}*/

			//比较。比较函数要自己写
			if (Compare((char *)base + j * width, (char *)base + (j + 1)* width) > 0)
			{
				//交换
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}

		}
	}
}

int main(void)
{
	test1();
	return 0;
}


在这里插入图片描述

总结

在这里插入图片描述
就如我这张图片上写的一样,好累,一个字都敲不出来,感觉下一秒就要闭上眼睛了,但是睡不着,因为很开心,这是我第一次写这么复杂的代码。今天把大家诟病的一款浏览器删掉了,换了一个浏览器,好像电脑是快了点,但联网又有了点问题,慢慢来,不懂的关于电脑的问题,慢慢解决。

和家人分享就是很开心嘞。

今天和大家的分享也就到这里了,如果你觉得有帮助的话,可不可以给小桃子点个赞呢?
感谢你的阅读。

我是小桃子,我爱这个世界。
2024年3月3日21:34 礼拜天 晴

  • 47
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值