【C语言】指针进阶[下](回调函数(模拟实现qsort-采用冒泡方式))

简单不先于复杂,而是在复杂之后。

 89efcc89ac61428db4d5b6639b2bd948.jpeg

目录

1. 回调函数 

1.1 qsort 函数的使用 

1.2 qsort 排序结构体类型 

1.3 回调函数模拟实现 qsort(排序整型) 

1.4 回调函数模拟实现 qsort(排序结构体类型)  


 

1. 回调函数 

回调函数就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

1.1 qsort 函数的使用 

首先演示一下 qsort 函数的使用

在之前我们写过冒泡排序,但我们只能排序整形数据;

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void bubble_sort(int arr[], int sz)
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序
		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;
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}

	}
}

int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

 

 

 我们想使用 qsort 函数,把需要传的参数依次输入后发现,我们需要自己写一个比较函数,比如我们想要比较两个整形,写出 cmp_int 函数,参数是 qsort 要求的(const void* e1, const void* e2), qsort函数对比较函数的返回值也有规定:

 把函数内容写完之后,发现 e1、e2 是 void* 的指针,是不能解引用的。

当我们写出这样的代码,发现用 char* 的指针来接收 int型变量的地址是不行的。

如果我们这样写:

 我们要想正确写出比较函数,那就可以将 e1、e2 强制类型转换成 int* 类型的指针:

 

 我们修改过后的代码过程还是比较繁琐,不妨这样写:

 

qsort 函数默认是把降序排成升序

如果我们想把升序排成降序,只需要把比较函数中 e1 和 e2 的位置调换一下就好,逻辑相反,就可以排成降序。

不要忘记使用 qsort 需要引头文件

#include<stdlib.h>

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>


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

int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz);

	qsort(arr, sz, sizeof(arr[0]), cmp_int);

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

	return 0;
}

1.2 qsort 排序结构体类型 

我们当然也可以使用 qsort 排序其他类型的数据,比如结构体类型:

假设我们按照名字来排序

 

 同理,我们也可以按照年龄来排序:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

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


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

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

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


void test_2()
{
	//测试使用 qsort 排序结构体数据
	struct Stu s[] = { {"zhangsan",15},{"lisi",30},{"wangwu",25} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//假设依据名字来排序
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);//假设依据年龄来排序

}

int main()
{
	test_1();//排序整型
	test_2();//排序结构体数据

	return 0;
}

void test_1()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz);

	qsort(arr, sz, sizeof(arr[0]), cmp_int);

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

}

1.3 回调函数模拟实现 qsort(排序整型) 

学会了使用 qsort 函数,那么我们也可以使用回调函数,模拟实现 qsort (采用冒泡的方式)

 

cmp 函数的参数不能简单地写成 (base + j, base + j +1)

因为我们并不知道要比较的数据是哪种类型,所以要改写成这样:

 下面是完整的使用回调函数,模拟实现 qsort (采用冒泡的方式)的代码:

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

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

void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}


void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				//交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = -1;
			}
		}
		if (flag == 1)
		{
			break;
		}

	}
}


void test_3()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//把数组排成升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]),cmp_int );

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

}



int main()
{
	//test_1();//排序整型
	//test_2();//排序结构体数据
	test_3();

	return 0;
}

1.4 回调函数模拟实现 qsort(排序结构体类型)  

我们使用回调函数,模拟实现 qsort (采用冒泡的方式)排序了整型的数据,当然也可以排序结构体类型的,只需要稍作修改:

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

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

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

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



void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}


void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		int flag = 1;//假设数组是排好序的
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				//交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = -1;
			}
		}
		if (flag == 1)
		{
			break;
		}

	}
}

void test_4()
{
	//测试使用 qsort 排序结构体数据
	struct Stu s[] = { {"zhangsan",15},{"lisi",30},{"wangwu",25} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);

}

int main()
{
	//test_1();//排序整型
	//test_2();//排序结构体数据
	//test_3();
	test_4();

	return 0;
}

同理,上面是按照年龄来排序,如果想按照名字排序,修改一下比较函数就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

2024_极限年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值