从排序算法的艺术看C语言qsort函数的魅力:一场数据的时空穿越

这篇具有很好参考价值的文章主要介绍了从排序算法的艺术看C语言qsort函数的魅力:一场数据的时空穿越。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎来到白刘的领域   Miracle_86.-CSDN博客

系列专栏  C语言知识

先赞后看,已成习惯

   创作不易,多多支持!

从排序算法的艺术看C语言qsort函数的魅力:一场数据的时空穿越,C语言知识,排序算法,c语言,算法,数据结构,学习方法,开发语言

目录

一 、回调函数

二、qsort函数

1.qsort函数排序整型数据

2.qsort函数排序结构数据


一 、回调函数

何为回调函数?听起来很装逼的样子,实际上它是一个很简单的概念:回调函数就是一个通过函数指针调用的函数。

就是说,你把一个函数的地址,作为参数传给另一个函数,当这个指针被调用时,被调用的函数就叫回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的条件发生时才被另一方调用,用于对该事件进行响应。

灵魂指针,教给(三)-CSDN博客

在上一篇博客中,我们实现了计算器。从一段冗余的代码,我们使用新学的转移表进行了优化。我们知道其本质是函数指针,那我们现在学习了回调函数,是不是也可以对其优化呢?

冗余代码:

#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a * b;
}
int div(int a, int b)
{
	return a / b;
}
int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	do
	{
		printf("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \n");
		printf(" 0:exit \n");
		printf("*************************\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = div(x, y);
			printf("ret = %d\n", ret);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}

我们会发现,每次都有这么一个小片段,很相似:

从排序算法的艺术看C语言qsort函数的魅力:一场数据的时空穿越,C语言知识,排序算法,c语言,算法,数据结构,学习方法,开发语言

这段代码其实只有调用函数的逻辑是有差异的,我们可以把调用函数的地址以参数的形式传过去,用函数指针接收,函数指针指向什么就调用什么函数,也就实现了回调函数的功能。

代码如下:

#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a * b;
}
int div(int a, int b)
{
	return a / b;
}
void calc(int(*pf)(int, int))
{
	int ret = 0;
	int x, y;
	printf("输入操作数:");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("ret = %d\n", ret);
}
int main()
{
	int input = 1;
	do {
		printf("******************\n");
		printf("* 1:add    2:sub *\n");
		printf("* 3:mul    4:div *\n");
		printf("*     0:exit     *\n");
		printf("******************\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(add);
			break;
		case 2:
			calc(sub);
			break;
		case 3:
			calc(mul);
			break;
		case 4:
			calc(div);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}

二、qsort函数

什么是qsort函数呢?它其实是Quicksort的缩写,也就是快速排序,简称快排。它可以对一个数组进行快速排序,支持自定义比较函数。我们之前学过冒泡排序:

灵魂指针,教给(二)-CSDN博客

但是冒泡排序,只能实现对整型数组的排序,而这个快速排序就比较牛逼了,它可以对任何类型的数据进行排序。

qsort函数的头文件是<stdlib.h>。

下面来看看qsort的原型:

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

 很长,我们一点一点来剖析。

它接收四个参数:

1.base:很好理解,中文是基础的意思,这里是要排序的数组的首元素地址。为什么是void*类型的呢?为了实现对任何类型的数据进行排序。

2.num:也很好理解,意思是数组的元素个数。类型是size_t也很好理解,因为数组元素个数不可能为负数。

3.size:这个是数组的元素的大小(单位字节)。

4.compar:它是一个函数指针,这个需要我们自己传进去,因为在设计这个函数的时候,它不会预料到我们今天要比较的是整型还是字符型或者是结构体,所以也就是我们自己来决定,在外部写一个比较函数,然后传进去。

前三个参数我们都很容易传参,这里着重说一下第四个参数:

我们需要自己写一个比较函数,来决定类型。比较函数的原型如下:

int compar(const void *p1, const void *p2);

比较函数 接受两个参数,返回值为整型。如果返回值小于0,则认为p1小于p2;如果返回值等于0,则认为p1等于p2;如果返回值大于0,则认为p1大于p2。

我们来练习一下:

1.qsort函数排序整型数据

其实这个函数很简单,我们只需要会写它的比较函数即可。

正常来讲,对于一个整型,我们习惯用>、<以及=来判断两个数据的大小。

正常我们可能写比较函数会这么写:

int int_cmp(const void* p1, const void* p2)
{
	if (*((int*)p1) > *((int*)p2))
		return 1;
	else if (*((int*)p1) == *((int*)p2))
		return 0;
	else
		return -1;
}

注意,我们p1和p2是void*类型的,不可以进行指针运算,所以我们要先对其进行强转。这里将(int*)p1也加上括号是因为强转是短暂的,所以加上比较保险,增强了代码可读性。

但是这么写还是不够好,我们可以这么写:

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

这样也可以实现功能,如果p1>p2,那返回大于0的数,其它同理。

这个是比较函数,我们来看总体代码:

#include <stdio.h>
//qsort函数的使⽤者得实现⼀个⽐较函数
int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
int main()
{
	int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int i = 0;

	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

 来看运行结果:

从排序算法的艺术看C语言qsort函数的魅力:一场数据的时空穿越,C语言知识,排序算法,c语言,算法,数据结构,学习方法,开发语言

2.qsort函数排序结构数据

首先我们定义一个结构体:

struct Stu //学⽣
{
	char name[20];//名字
	int age;//年龄
};

还是先来分析比较函数:

整型我们可以用>、<,那字符型,我们可以使用一个函数,叫strcmp(以后我们会详细介绍,继续挖坑),今天就简单介绍一下怎么用的。

它的原型是:

int strcmp(const char *str1, const char *str2);

该函数会比较字符串str1和str2,并根据比较结果返回一个整数值。

如果str1和str2相等,则返回0;如果str1小于str2,则返回一个负数;如果str1大于str2,则返回一个正数。

比较的规则是按照字符的ASCII码值依次进行比较,从字符串的第一个字符开始比较,直到遇到不相等的字符或者字符串的结束标志'\0'。不会考虑字符串的长度。

str1 = "abcd";
str2 = "abc";
//str1 > str2

str1 = "abz";
str2 = "abccccc";
//str1 > str2

回归正题,我们怎么比较结构体呢?我们可以看到,结构体里有两个成员变量,一个是字符串-姓名,一个是整型-年龄。所以我们可以有两种方法,一种是按姓名首字母来排序,一种是按年龄大小。也就是一种是用strcmp,一种是用>、<。

方法了解了,我们还要来复习一下如何访问结构体成员。

武器大师——操作符详解(下)-CSDN博客

我们之前讲过,如果传地址的话,使用->来访问,

所以先来看按姓名来排序:

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

同样,对于void*类型的p1、p2,我们还是要强制类型转换,之后访问的结果传到strcmp函数中,比较出的结果再return。

整型就更简单了:

int cmp_stu_by_age(const void* e1, const void* e2)
{
 return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

来看总代码:文章来源地址https://www.toymoban.com/news/detail-841520.html

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu //学⽣
{
	char name[20];//名字
	int age;//年龄
};
//假设按照年龄来⽐较
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//strcmp - 是库函数,是专⻔⽤来⽐较两个字符串的⼤⼩的
//假设按照名字来⽐较
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照年龄来排序
void test2()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
//按照名字来排序
void test3()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}
int main()
{
	test2();
	test3();
	return 0;
}

到了这里,关于从排序算法的艺术看C语言qsort函数的魅力:一场数据的时空穿越的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【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日
    浏览(31)
  • 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日
    浏览(32)
  • 【C语言】——指针六:冒泡排序与qsort函数的实现

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

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

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

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

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

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

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

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

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

    2024年02月14日
    浏览(32)
  • 模拟实现qsort函数(采用冒泡排序的方式)

    前言: 之前我在C语言:指针详解【进阶】后篇中提到了 qsort函数 , qsort函数 作为一个库函数,在我们日常的代码编写中可能会用到,在上面提到的文章中我们也进行使用了这个函数,大家也了解了一些这个函数的使用方法,但我们作为学习者,我们不仅要会用,还要知道这

    2024年02月05日
    浏览(33)
  • C语言调试大作战:与VS编译器共舞,上演一场“捉虫记”的艺术与科学

    少年们好,我是博主 那一脸阳光 ,我们接下来介绍C语言的调试和bug的分享。 引言: “如果你曾经在深夜与一串神秘莫测的C代码狭路相逢,彼此瞪大眼睛,犹如牛仔对决般紧张刺激;或者你曾试图驯服一段狂野不羁的循环,却发现自己陷入了一个深不见底的逻辑黑洞,那么

    2024年01月16日
    浏览(33)
  • c语言用冒泡排序模拟实现qsort排序

    1、简单介绍冒泡排序 冒泡排序就是两两相邻元素进行比较,如果不满足顺序就进行交换。现有一组整数,将其用冒泡排序实现排序为升序。 假设有这样一组整数:9 8 7 6 5    由此可知,如果一个整型数组有num个元素,则需走num-1趟,若走在第i趟,则在第i趟内需要比较num-1

    2024年02月15日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包