C语言:对数据进行快速排序->qsort(quick sort)函数的使用

本文详细介绍了C语言中的qsort函数,包括其工作原理、参数解释、如何自定义compar函数以及如何根据不同数据类型使用。通过实例演示,帮助新手掌握qsort函数在排序各种类型数据中的应用。
摘要由CSDN通过智能技术生成

零、前言->qsort函数能干嘛?

很多新手和小白在学习和使用C语言的过程中,面对各种类型的数据需要进行排序时,很难一次性的把各种类型的数据一次性排序。

只要你刚学过C语言的函数基本规则,就能使用它。qsort函数简单易上手,此篇文章将让读者能够入门使用qsort函数,帮你解决数据排序的烦恼!


一、了解->什么是qsort(quick sort)函数?(不想了解的可以直接跳到第二节)

在官方的Cpp网站中,对qsort函数的定义如下:

原文请点击:

cplusplus.com/reference/cstdlib/qsort/

给出了形参,就等于告诉了我们怎么使用这个函数。

————未月五(shenjingbing)

qsort函数的形参由四部分组成:

1.void* base:

需要排序的数组的首元素地址

之所以写成void*,是因为该形参可以接收任何种类的地址(如char* ,int*都可以被*void*接收),也就能够进行各种数据类型(整型、字符型、浮点型、结构体等等)的排序了。

base(译为基础),非要理解的话,在这里可以理解成数组的首元素。


2.size_t num:

需要排序的数组的元素个数。size_t是unsigned int(无符号整型)的意思。

通常用以下代码来计算元素个数:

int arr[] = { 9,8,7,6,5,4,3,2,1,0 };//以该数组为例
int sz = sizeof(arr) / sizeof(arr[0]);

3.size_t size

需要排序的数组内每个元素的字节大小

通常用 sizeof(arr[0]来表示每个元素字节大小。


4.int(*compar)(const void*,const void*

自定义的compar函数。不要看见自定义就犯愁,其实很简单!

int(*compar)(const void*,const void*)是一个函数指针,指向compar函数。不了解函数指针的读者没有关系,下文会讲解怎么使用。

因为qsort函数不知道我们需要排序的数组是什么数据类型,(是char、int还是结构体呢?)所以让我们自己定义compar函数,才能实现各种数据类型的排序。

上面也提过,之所以写成void*,是因为该形参可以接收任何种类的地址(如char* ,int*都可以被*void*接收),也就能够进行各种数据类型(整型、字符型、浮点型、结构体等等)的排序了。


那么如何自定义compar函数呢?

 原文请点击:

cplusplus.com/reference/cstdlib/qsort/

qsort函数要求自定义的compar函数返回值分成三种:

图3

(还是以整型数组为例)

翻译成人话,就是定义的时候,如果前面的元素比后面的元素小,需return小于0的值;

                                                  如果相等,需要返回0;

                                                  如果前面的元素比后面的元素大,需return大于0的值。

int cmp_int(const void* p1, const void* p2)//以int类型数据为例
{
	return *(int*)p1 - *(int*)p2;
}

所以作差是定义compar函数一种比较好的方式。(注意,double数组千万不能作差!要用三目操作符:)

在对浮点或者double型的一定要用三目运算符,因为如果也使用整型那样的想减的话,如果是两个很接近的数则可能返回一个小数(大于-1,小于1),而cmp的返回值是int型,因此会将这个小数返回0,系统认为是相等,失去了本来存在的大小关系。

原文链接(感谢大佬指点):

qsort细节用法,double型的排序我竟然一直用错了~~~_qt 浮点数排序-CSDN博客

compar函数的形参是数组的前后两个元素(*p1和*p2在qsort函数内部已经和自定义的compar函数进行过联系了),本例子是int类型的数组,所以有强制转换成int*的操作。再对强制转换成int*的指针变量p进行解引用,就可以得到图3qsort函数要求的返回值。

下面就讲一讲怎么使用qsort函数。


二、qsort函数的使用(不用看本文第一节,直接套就行)

Step1:加上#include<stdlib.h>头文件

Step2:确定你的数组是什么数据类型(int arr[10]、double arr[10]、char arr[10]等等)


int arr[10] = { 33,24,53,53,67,44,24,22,312,36};

这就是int


double arr[10] = { 1.22,2.33,3.44,4.55,5.66,6.77,7.88,8.99,9.11,10.33};

这是double


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

struct stu s[] = { {"mingming",13},{"xiaomei",15},{"lihua",40}};//李华应该得40了吧

这是结构体


Step3:自定义cmp函数(默认升序,想要做降序排列,就把p1改成p2,p2改成p1)


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

这是int,常用作差法


int cmp_double(const void* p1, const void* p2)
{
	return *(double*)p1 > *(double*)p2 ? 1 : -1;
}

这是double,常用三目操作符


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

这是结构体的字符串,用strcmp函数(需头文件#include<string.h>)对两个字符串进行比较(按26个字母的顺序进行排序,第一个字母相同就再比下一个字母)


Step4:套进qsort函数里

qsort(arr, sz, sizeof(arr[0]), cmp_int);//cmp_int是step3自定义的函数名字

分别写四个参数:qsort(数组名,元素个数,每个元素的字节大小,compar函数的名字);


Step5:打印出来验证一下排序是否成功

注意我测试的是整型,所以是int arr[]和%d打印。如果测试double型要灵活改动(下面有示例)

void print(int arr[], int sz)//注意我测试的是整型,所以是int arr[]。如果测试double型要灵活改动
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);//如果是double型要改成%lf,其他类型同理
	}

示例:

int型
#include<stdio.h>
#include<stdlib.h>//qsort函数需要该头文件来实现

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

void print(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
tese_int() //把整型数组排序放在一个模块里面测试
{
	int arr[10] = { 33,24,53,53,67,44,24,22,312,36};//需要排序的乱序int型数组;
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr, sz);//打印排序好的数组
}
int main()
{
	tese_int();
	return 0;
}


double型
#include<stdio.h>
#include<stdlib.h>
int cmp_double(const void* p1, const void* p2)
{
	return *(double*)p1 > *(double*)p2 ? 1 : -1;
}

void print_arr(double arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%lf ", arr[i]);
	}
	printf("\n");
}

test_double()
{
	double arr[] = { 1.11,3.33,8.88,4.44,6.66,7.77,5.55,2.22,9.99 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_double);
	print_arr(arr, sz);
}


int main()
{
	//tese_int();
	test_double();
	return 0;
}


结构体(字符串)
#include<stdio.h>
#include<stdlib.h>//qsort函数需要该头文件来实现
#include<string.h>

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

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

void test_struct_by_string()
{
	struct stu s[] = { {"mingming",13},{"xiaomei",15},{"lihua",40} };//李华应该得40了吧
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}

int main()
{
	//tese_int();
	//test_double();
	test_struct_by_string();
	return 0;
}

才疏学浅,如有纰漏请大佬不吝赐教!

  • 32
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值