基于函数回调方法对qsort()进行修改,使用冒泡排序实现对不同类型数据的排序

目录

一、什么是函数回调

二、qsort()快速排序

1. 库函数qsort()的声明

2. qsort()对不同类型数据进行排序示例

2-1先输入需要排序的不同类型数据:

2-2对qsort()需要的实参,即首元素地址,元素个数,元素大小,比较函数进行计算和输入。

2-3排序方法函数的建立

2-4打印各类数据的函数

2-5完整代码

三、冒泡排序实现不同类型数据的排序

3-1建立交换前后参数

3-3全部代码

 


一、什么是函数回调

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

二、qsort()快速排序

1. 库函数qsort()的声明

void qsort(void *base,//指向要排序的数组的第一个元素的指针。
           size_t nitems,//指向要排序的数组的第一个元素的指针。
           size_t size,//数组中每个元素的大小,以字节为单位。
           int (*compar)(const void *, const void*)//用来比较两个元素的函数。
           ) 
   
  1. base -- 指向要排序的数组的第一个元素的指针,因为不知传入的实参是什么类型,所以形参是无参数类型void。
  2. nitems -- 由 base 指向的数组中元素的个数。
  3. size -- 数组中每个元素的大小,以字节为单位,由此可知传入参数的类型,如int为四个字节,char为一个字节。
  4. compar -- 用来比较两个元素的函数,这个函数需要自己创建一个函数,确定比较方法。

2. qsort()对不同类型数据进行排序示例

2-1先输入需要排序的不同类型数据:

#include<stdio.h>

struct St
{    
    char name[40];
    int age;
    float score;
} St;
int main()
{
	int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型数据示例
	char arr2[] = "hello";//字符型数据示例
	struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};
    //结构体数据示例
	
	return 0;
}

2-2对qsort()需要的实参,即首元素地址,元素个数,元素大小,比较函数进行计算和输入。

因结构体内部成员不同,因此按照每个成员的排序顺序也不同,以本文为例,分为以姓名排序(以首元素的ascii码值的大小进行排序)、以年龄排序、以成绩排序三种,因此要写不同的排序函数。

int main()
{
	int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型示例
	char arr2[] = "hello";//字符示例
	struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体示例
	int szarr1 = sizeof(arr1) / sizeof(arr1[0]);//整型元素个数
	int szarr2 = sizeof(arr2) / sizeof(arr2[0]);//字符元素个数
	int szs= sizeof(s) / sizeof(s[0]);//结构体元素个数
	qsort(arr1, szarr1, sizeof(arr1[0]), cmp_int);//整型排序
	qsort(arr2, szarr2, sizeof(arr2[0]), cmp_char);//字符排序
	qsort(s, szs, sizeof(s[0]), cmp_st_by_name);//结构体按姓名排序
	qsort(s, szs, sizeof(s[0]), cmp_st_by_age);//结构体按年龄排序
	qsort(s, szs, sizeof(s[0]), cmp_st_by_score);//结构体按成绩排序
	return 0;
}

2-3排序方法函数的建立

计算前面的数e1与后面的数e2的差,大于0则返回正数,则交换,小于0则返回复数,不交换,打印出来为正序,若要求逆序,则改成e2-e1

int cmp_int(const void *e1, const void *e2)//比较整型方法
{
	return *((int*)e1)-*((int*)e2);
}
int cmp_char(const void* e1, const void* e2)//比较字符型方法
{
	return strcmp(e1, e2);//strcmp()比较字符串大小,用ascii码值比较
}
int cmp_st_by_name(const void* e1, const void* e2)//以姓名排序比较结构体方法
{
	return strcmp(((struct St*)e1)->name, ((struct St*)e1)->name);
}
int cmp_st_by_age(const void* e1, const void* e2)//以年龄排序比较结构体方法
{
	return ((struct St*)e1)->age-((struct St*)e2)->age;
}
float cmp_st_by_score(const void* e1, const void* e2)//以分数排序比较结构体方法
{
	if (((struct St*)e1)->age > ((struct St*)e2)->age)
		return 1;
	else if (((struct St*)e1)->age < ((struct St*)e2)->age)
		return -1;
	else 
		return 0;

}

2-4打印各类数据的函数

void print_int(const int *arr, const int sz)//打印整型
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%d", arr[i]);
	}
	printf("\n");

}
void print_char(const char* arr, const int sz)//打印字符串
{
	int i=0;
	for (i = 0; i < sz; i++)
	{
		printf("%c", arr[i]);
	}
	printf("\n");

}
void print_st(const struct St* arr, int sz)//打印结构体类型数据
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%s %d %.1f, ",arr[i].name,arr[i].age,arr[i].score);
	}
	printf("\n");

}

2-5完整代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct St
{	
	char name[40];
	int age;
	float score;
} St;
void print_int(const int *arr, const int sz)//打印整型
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%d", arr[i]);
	}
	printf("\n");

}
void print_char(const char* arr, const int sz)//打印字符串
{
	int i=0;
	for (i = 0; i < sz; i++)
	{
		printf("%c", arr[i]);
	}
	printf("\n");

}
void print_st(const struct St* arr, int sz)//打印结构体类型数据
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%s %d %.1f, ",arr[i].name,arr[i].age,arr[i].score);
	}
	printf("\n");

}
int cmp_int(const void *e1, const void *e2)//比较整型方法
{
	return *((int*)e1)-*((int*)e2);
}
int cmp_char(const void* e1, const void* e2)//比较字符型方法
{
	return strcmp(e1, e2);//strcmp()比较字符串大小,用ascii码值比较
}
int cmp_st_by_name(const void* e1, const void* e2)//以姓名排序比较结构体方法
{
	return strcmp(((struct St*)e1)->name, ((struct St*)e1)->name);
}
int cmp_st_by_age(const void* e1, const void* e2)//以年龄排序比较结构体方法
{
	return ((struct St*)e1)->age-((struct St*)e2)->age;
}
float cmp_st_by_score(const void* e1, const void* e2)//以分数排序比较结构体方法
{
	if (((struct St*)e1)->age > ((struct St*)e2)->age)
		return 1;
	else if (((struct St*)e1)->age < ((struct St*)e2)->age)
		return -1;
	else 
		return 0;

}

int main()
{
	int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型示例
	char arr2[] = "hello";//字符示例
	struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体示例
	int szarr1 = sizeof(arr1) / sizeof(arr1[0]);//整型元素个数
	int szarr2 = sizeof(arr2) / sizeof(arr2[0]);//字符元素个数
	int szs= sizeof(s) / sizeof(s[0]);//结构体元素个数
	qsort(arr1, szarr1, sizeof(arr1[0]), cmp_int);//整型排序
	qsort(arr2, szarr2, sizeof(arr2[0]), cmp_char);//字符排序
	qsort(s, szs, sizeof(s[0]), cmp_st_by_name);//结构体按姓名排序
	print_st(s, szs);
	qsort(s, szs, sizeof(s[0]), cmp_st_by_age);//结构体按年龄排序
	print_st(s, szs);
	qsort(s, szs, sizeof(s[0]), cmp_st_by_score);//结构体按成绩排序
	print_st(s,szs);
	print_int(arr1, szarr1);
	print_char(arr2, szarr2);
	return 0;
}

输出结果:

lisi 21 80.0, wangwu 22 56.5, zhangsan 20 90.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
022345679
ehllo

 

三、冒泡排序实现不同类型数据的排序

使用冒泡排序方法进行排序和qsort()需要的参数类似,利用的比较函数是相同的,只是排序的方法有差异,只需自行建立冒泡排序的函数代替qsort()即可。

3-1建立交换前后参数

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++;
		//一对字节一对字节交换
	}
}

因为Swap的形参是char*类型,一次只能访问一个字节,因此对调时是一个字节一个字节对调,加入字节长度可知有几个字节要对掉,也就是要对调的次数,创建一个循环实现。

反观以下普通冒泡排序实现数字交换功能时,因传入的形参是int*,一次就能访问四个字节,只要交换一次,解引用后就可以访问到形参接收到的指针指向的参数的值,不用再设置循环。

void exchange(int* a, int* b)
{
	int tmp = 0;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

3-2冒泡函数主体


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 j = 0;
		for (j = 0; j < sz - 1 - i; j++)//一趟中两个交换
		{
			//if (arr[j] > arr[j + 1])
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
//base的类型是void,不能直接加j,而不知传入的实参是什么类型,所以转换成占一个字节的char类型,
//加j*wide能跳过j个宽度的字节,宽度就是传入实参的字节长度
			{
				//两个元素的交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

3-3全部代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct St
{	
	char name[40];
	int age;
	float score;
} St;
void print_int(const int *arr, const int sz)//打印整型
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%d", arr[i]);
	}
	printf("\n");

}
void print_char(const char* arr, const int sz)//打印字符串
{
	int i=0;
	for (i = 0; i < sz; i++)
	{
		printf("%c", arr[i]);
	}
	printf("\n");

}
void print_st(const struct St* arr, int sz)//打印结构体类型数据
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%s %d %.1f, ",arr[i].name,arr[i].age,arr[i].score);
	}
	printf("\n");
}

int cmp_int(const void *e1, const void *e2)//比较整型方法
{
	return *((int*)e1)-*((int*)e2);
}
int cmp_char(const void* e1, const void* e2)//比较字符型方法
{
	return strcmp(e1, e2);//strcmp()比较字符串大小,用ascii码值比较
}
int cmp_st_by_name(const void* e1, const void* e2)//以姓名排序比较结构体方法
{
	return strcmp(((struct St*)e1)->name, ((struct St*)e1)->name);
}
int cmp_st_by_age(const void* e1, const void* e2)//以年龄排序比较结构体方法
{
	return ((struct St*)e1)->age-((struct St*)e2)->age;
}
float cmp_st_by_score(const void* e1, const void* e2)//以分数排序比较结构体方法
{
	if (((struct St*)e1)->age > ((struct St*)e2)->age)
		return 1;
	else if (((struct St*)e1)->age < ((struct St*)e2)->age)
		return -1;
	else 
		return 0;

}
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 j = 0;
		for (j = 0; j < sz - 1 - i; j++)//一趟中两个交换
		{
			//if (arr[j] > arr[j + 1])
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
				//base的类型是void,不能直接加j,而不知传入的实参是什么类型,所以转换成占一个字节的char类型,加j*wide能跳过j个宽度的字节,宽度就是传入实参的字节长度
			{
				//两个元素的交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}
int main()
{
	int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型示例
	char arr2[] = "hello";//字符示例
	struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体示例
	int szarr1 = sizeof(arr1) / sizeof(arr1[0]);//整型元素个数
	int szarr2 = sizeof(arr2) / sizeof(arr2[0]);//字符元素个数
	int szs= sizeof(s) / sizeof(s[0]);//结构体元素个数
	bubble_sort(arr1, szarr1, sizeof(arr1[0]), cmp_int);
	bubble_sort(arr2, szarr2, sizeof(arr2[0]), cmp_char);
	bubble_sort(s, szs, sizeof(s[0]), cmp_st_by_name);
	print_st(s, szs);
	bubble_sort(s, szs, sizeof(s[0]), cmp_st_by_age);
	print_st(s,szs);	
	bubble_sort(s, szs, sizeof(s[0]), cmp_st_by_score);
	print_st(s, szs);
	print_int(arr1, szarr1);
	print_char(arr2, szarr2);
	return 0;
}

 

输出结果:

zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
022345679
ehllo
-

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值