qsort函数用法,举例使用qsort函数

回顾冒泡排序

1.原理:两两元素进行比较,不满足顺序就交换
2.将一组数排成升序

int main()
{
	int arr[10] = { 1,5,4,7,6,8,9,2,3,0 };
	//排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0;i < sz-1;i++)//有n个数,进行n-1趟比较
	{
		int j = 0;
		for (j = 0;j < sz - i - 1;j++)//第二趟比较的对数比第一趟少一
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
	for (i = 0;i < sz;i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

运行结果:
qsort函数用法,举例使用qsort函数_第1张图片
3.但是,该代码有局限性,只能排同一种类型的数据。
引出qsort函数:qsort函数可以排序不同种类型的数据

qsort函数用法

一.qsort函数介绍

是库函数,使用时引用头文件,返回值类型为void,有四个参数,如下图
qsort函数用法,举例使用qsort函数_第2张图片

二.qsort函数参数

qsort函数用法,举例使用qsort函数_第3张图片
参数一:void ∗ * base:是一个指针,指向被排序数组的首元素
参数二:size_t num:被排序的数组中的元素个数
参数三:size_t size:被排序数组中每个元素的大小
(size_t是unsigned int类型)
参数四:是函数指针类型,指向函数,该函数用于比较base指针指向的数组中的两个元素(后面详细介绍)

三.关于qsort函数第一个参数:void ∗ * 类型指针

☀️(1)void ∗ * 类型指针的特点

1.可以接收任何类型的地址,即可以指向任何类型的数据。一般指针类型要和所指向的数据类型相匹配,比如int*只能指向int类型的数据;但void ∗ * 指针可以指向任何类型的数据。
2.void ∗ * 类型的指针不可以直接解引用,也不可直接进行指针运算。

☀️(2)void ∗ * 类型指针的使用方法

将void*类型强制转换为想要的类型。一般强制转换为char ∗ * 类型,因为char ∗ * 类型的指针每次只能访问一个字节,用char ∗ * 乘以所访问元素的大小即可每次跳过该元素类型大小个字节数

四.关于qsort函数第四个参数

☀️(1)第四个参数的本质

1.参数是一个函数指针
2.函数指针类型名:int ( ∗ * )(const void ∗ * ,const void ∗ * )
3.该函数指针所指向的函数用来排两个元素的顺序,是一个回调函数(这里自定义该回调函数名称为int_cmp)

☀️(2)回调函数int_cmp

1.函数int_cmp返回类型为int、函数的两个参数类型均为void ∗ *
2.该函数用来排两个元素的顺序
3.若int_cmp返回值小于0,则被指针base指向的一组元素被排升序;若int_cmp返回值大于0,则被指针base指向的一组元素被排降序

五.qsort函数内部过程

参数一:指针类型,void ∗ *
参数二:整型,表数组大小; 参数三:整型,表数组元素大小
参数四:函数指针类型;

1.通过第一个指针类型的参数得到被排序数组的首元素地址
2.通过第二、三个整形类型参数得到被排序数组的元素个数以及每个元素大小(此时就可以通过指针的加减访问到数组内部的每个元素了)
3.指针类型的参数一按数组下标顺序每次将两个指针传给第四个函数指针类型的参数
4.第四个函数指针类型的参数指向一个函数,该函数对接收到的两个指针解引用,返回两个解引用后的数的差
5.判断函数返回值,如果返回值小于0,则参数一传给参数四的两个指针指向的元素顺序不变;如果返回值大于0,则参数一传给参数四的两个指针指向的元素顺序改变
6.当数组中的所有元素一次被两两排序后,最终即可得到按顺序排列的一串数

六.为什么可以通过函数cmp_int的返回值对元素排序?

传进来两个参数:void ∗ * p1和void ∗ * p2,强制转化为int ∗ * 类型后(当然也可以转换为别的类型),变成int ∗ * p1和int ∗ * p2

☀️(1)返回值中计算顺序与传参顺序相同时

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

1. ∗ * (int ∗ * )p1< ∗ * (int ∗ * )p2时
①返回值 ∗ ∗ (int ∗ * )p1- ∗ * (int ∗ * )p2<0
②qsort函数接收到的cmp_int函数的返回值小于0,两参数顺序不变
③最终两元素的顺序:先 ∗ * p1,后 ∗ * p2,升序
2. ∗ * (int ∗ * )p1> ∗ * (int ∗ * )p2时
①返回值 ∗ ∗ (int ∗ * )p1- ∗ * (int ∗ * )p2>0
②qsort函数接收到的cmp_int函数的返回值大于0,两参数顺序调换
③最终两元素的顺序:先 ∗ * p2,后 ∗ * p1,升序
3.当被指针base(第一个参数)指向的数组中所有元素都经过cmp_int函数的排序后,数组就被排成了升序
结论:传的顺序和相减的顺序一致,则升序

☀️(2)返回值中计算顺序与传参顺序相反时

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

1. ∗ * (int ∗ * )p1< ∗ * (int ∗ * )p2时
①返回值 ∗ ∗ (int ∗ * )p2- ∗ * (int ∗ * )p1>0
②qsort函数接收到的cmp_int函数的返回值大于0,两参数顺序调换
③最终两元素的顺序:先 ∗ * p2,后 ∗ * p1,降序
2. ∗ * (int ∗ * )p1> ∗ * (int ∗ * )p2时
①返回值 ∗ ∗ (int ∗ * )p2- ∗ * (int ∗ * )p1<0
②qsort函数接收到的cmp_int函数的返回值小于0,两参数顺序不变
③最终两元素的顺序:先 ∗ * p1,后 ∗ * p2,降序
3.当被指针base(第一个参数)指向的数组中所有元素都经过cmp_int函数的排序后,数组就被排成了升序
结论:传的顺序和相减的顺序相反,则降序

七.调控qsort函数升降序以及例子

☀️(1)无脑记结论

结论:传的顺序和相减的顺序一致,则升序,如图

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

结论:传的顺序和相减的顺序相反,则降序

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

☀️(2)使用qsort函数排序例子

1.排整型数组

①用qsort函数将数组排成升序(降序)

#include
void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
		printf("%d ", arr[i]);
}
int cmp_int(const void* p1, const void* p2)
{
	return(*(int*)p1 - *(int*)p2);
	//当相减顺序为*(int*)p2-*(int*)p1时,降序
}
test1()
{
	int arr[10] = { 1,3,5,7,9,2,4,6,8,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(int), cmp_int);
	print(arr, sz);
}
int main()
{
	test1();
	return 0;
}

运行结果:
qsort函数用法,举例使用qsort函数_第4张图片

2.排结构体数组

①.按年龄升序排

#include
struct Stu
{
	char name[20];//20个字节
	int age;//4个字节
	//这个结构体变量的大小是24(字节)
};
void print(struct Stu* stru_stu, int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%d ", stru_stu[i].age);
	}
}
int cmp_stu_by_age(const void* p1, const void* p2)
{
	return((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
test2()
{
	struct Stu arr[] = { {"Zip",25},{"Lisa",20},{"Wu",30} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
	print(arr, sz);
}
int main()
{
	test2();
}

把升序年龄打印出来:
qsort函数用法,举例使用qsort函数_第5张图片
②.按姓名降序排

#include
#include
struct Stu
{
	char name[20];//20个字节
	int age;//4个字节
	//这个结构体变量的大小是24(字节)
};
void print(struct Stu* stru_stu, int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%s ", stru_stu[i].name);
	}
}
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p2)->name ,((struct Stu*)p1)->name);
}
test3()
{
	struct Stu arr[] = { {"Zip",25},{"Lisa",20},{"Wu",30} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
	print(arr, sz);
}
int main()
{
	test3();
}

把降序姓名(字符串)打印出来
qsort函数用法,举例使用qsort函数_第6张图片
注:cmp_stu_by_name函数的返回值是strcmp(((struct Stu*)p2)->name ,((struct Stu*)p1)->name),两字符串的比较不能相减,要用到strcmp函数。strcmp函数中,前字符串大于后字符串,返回结果大于0,前字符串小于后字符串时,返回结果小于0。

你可能感兴趣的:(c语言)