c学习笔记——自定义qsort函数

目录

一、前言

 二、从MSDN认识qsort

1.分析:

2.void*的特殊性

三、cmp_函数的实现

1.比较int类型数据

2.比较char类型数据

3.比较float类型函数

4.比较结构体类型函数

四、bubble_sort函数的实现

分析:

五、swap函数的实现

六、重难点总结


一、前言

   我们学习过的冒泡排序,插入排序,选择排序等经典排序方法,为我们数据排序提供了稳定思路,但局限在于排序数据类型的单一。为了解决这一问题,c语言中提供了库函数qsort解决。我们今天就通过自定义函数实现qsort的功能,排序方法采用基本的冒泡排序


 二、从MSDN认识qsort

 

 

1.分析:

我们需要传入四个变量:base——待排序数组的首元素地址;

                                        num——数组内的元素个数;

                                        width——每个元素的大小(单位为字节);

                                       函数指针——传入两个数的地址,比较二者大小(需自己设计)

2.void*的特殊性

1.可以传入任何类型的指针而不会报警告,适合我们实现任何数据类型排序的目的;

2.不可以对其进行解引用操作,除非通过强制类型转换()确定其具体类型;

3.不可以对其进行加减运算,原因是不知道类型所以不知道步长,因此还是需要强制类型转换


三、cmp_函数的实现

注意:都需要先进行强制类型转换才可以解引用

1.比较int类型数据

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

2.比较char类型数据

char类型数据不可以用<>=进行比较,所以要用函数strcmp库函数,头文件为#include<string>

int cmp_char(const void*e1, const void*e2)
{
	return strcmp((char*)e1, (char*)e2);
}

3.比较float类型函数

因为返回的是int类型,所以我们加入了判断语句。用数的正负表示数的大小情况

int cmp_float(const void*e1, const void*e2)
{
	if ((float*)e1 > (float*)e2)
		return 1;
	else if ((float*)e1 ==(float*)e2)
		return 0;
	else
		return -1;
}

4.比较结构体类型函数

结构体数组元素不可以直接比较,必须先选出结构体某一内容进行比较

typedef struct book{ 

	char name[20];
	int prince;
                   }b;//重命名struct book为b


int cmp_stru_price(const void*e1, const void*e2)
{
	return ((b*)e1)->prince - ((b*)e2)->prince;
}

注意!!!(b*)e1外面的括号不可以省略,因为->的优先级比强制类型转换高


四、bubble_sort函数的实现

首先思考一个问题:既然传入的指针为void*类型,如何实现步长的确定?聪明的科学家想到利用width作为我们的标准

void bubble_sort(void*base,int sz,int width,int(*cmp)(void*,void*))
{
	int i; int j;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1-i; j++)
		{
			if (cmp((char*)base + width*j, (char*)base + width*(j + 1))>0)
			{
				swap((char*)base + width*j, (char*)base + width*(j + 1),width);
			}
		}

	}
}

分析:

1.int(*)(void*,void*)是一个函数指针,指向我们之前设计的大小比较函数

2.在使用base的时候要先强制类型转换才可以作加减运算

3.漂亮的地方在于,不管实际传入的base是什么类型,我们都将其转化为char*类型的指针,因为char*的步长最小为1,加上width就可以准确指向下一个 

以int为例,width为4,所及就可以指向下一个元素


五、swap函数的实现

void swap(char*buff1,char*buff2,int width)
{
	int i;
	for (i = 0; i < width; i++)
	{
		int tmp = *buff1;
		*buff1 = *buff2;
		*buff2 = tmp;
		buff1++;
		buff2++;

	}

}

值得关注的是,交换不是一次就可以了,因为我们现在是char*类型的指针,如上图所画,一次只能交换一格,如交换int的,要交换4次


六、重难点总结

1.函数指针的使用,使我们每次只需导入大小比较函数的地址即可,而不必写多个函数,分别含有不同的大小比较函数,减少了重复代码的出现

 2.width的使用相当于告诉了我们进行比较的数组元素的类型,满足我们实现各种数据类型排序的需求

3.void*函数海纳百川,方便了我们的输入,只是注意在使用时的强制类型转化,否则无法使用


希望上述的总结对大家的理解有帮助,也更好的欣赏回调函数(这里为用函数指针调用函数)的魅力。

  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 好的,针对您的问题,qsort函数需要一个比较函数作为参数,用于排序元素。比较函数需要满足以下条件: 1. 比较函数的参数为两个const void类型的指针,指向要比较的元素。 2. 比较函数返回一个int类型的值,表示两个元素的大小关系。 如果返回值为负数,表示第一个元素小于第二个元素;如果返回值为零,表示两个元素相等;如果返回值为正数,表示第一个元素大于第二个元素。 以下是一个例子: ``` int cmp(const void *a, const void *b) { int *pa = (int *)a; int *pb = (int *)b; return (*pa - *pb); } ``` 在这个例子中,比较函数的参数为两个const void类型的指针a和b,需要将它们转换成int类型的指针,然后通过解引用来获取它们所指向的值。比较函数返回的是两个元素的差值,即a-b,表示如果a<b,则返回负数,如果a=b,则返回0,如果a>b,则返回正数。 希望这个例子能够对您有所帮助! ### 回答2: 在C语言中,qsort函数用于实现快速排序算法。为了使用qsort函数对数组进行排序,我们需要编写一个比较函数(compar函数)来指定元素的比较规则。 比较函数是一个用于比较两个元素的函数,它的原型如下: int compar(const void *a, const void *b); 其中,a和b是需要比较的元素的指针。比较函数需要返回一个整数值,表示两个元素的大小关系。具体的返回值规则如下: - 若a < b,则返回负数; - 若a = b,则返回0; - 若a > b,则返回正数。 编写比较函数的时候,我们可以根据自己的需求定义比较规则。下面是一个简单的例子,比较函数用于按照元素的大小进行升序排序: int compar(const void *a, const void *b) { int num1 = *(int*)a; // 将a转换为整数指针并取值 int num2 = *(int*)b; // 将b转换为整数指针并取值 return num1 - num2; // 返回两数的差值 } 在这个例子中,我们将a和b转换为整数指针,并使用*操作符取得它们的值。然后,我们返回num1减去num2的结果,这样可以按照元素的大小进行升序排序。 要注意的是,比较函数的参数类型是const void*,这是因为在排序时,qsort函数不关心元素的具体类型,而是根据传入的参数类型进行比较。所以,在比较函数中,我们需要根据具体的需求来进行类型转换。 最后,将比较函数作为qsort函数的参数传入,即可通过调用qsort函数来对数组进行排序。比如: int array[] = {4, 2, 3, 1, 5}; int size = sizeof(array) / sizeof(array[0]); qsort(array, size, sizeof(int), compar); 这样,数组array将会按照元素的大小进行升序排序。 ### 回答3: 在C语言中,使用qsort函数需要编写一个比较函数,以便对数组进行排序。比较函数的编写有以下几个要点: 1. 函数原型:比较函数的原型应该符合qsort函数的要求,形如:int compare(const void *a, const void *b)。其中,参数a和b是要比较的两个元素的指针。 2. 返回值:比较函数应该返回一个整数值,表示a和b的关系。如果返回值小于0,则a应该排在b的前面;如果返回值大于0,则a应该排在b的后面;如果返回值等于0,则a和b的相对顺序不变。 3. 类型转换:由于qsort函数的参数是指向void的指针,因此在比较函数内部需要进行类型转换,将参数转换为实际的类型,然后进行比较。 4. 比较的实现:根据实际需求,比较函数可以使用各种比较算法来实现。例如,对于整数数组,可以直接使用减法操作符来比较a和b的大小;对于字符串数组,可以使用strcmp函数比较两个字符串的大小。 下面是一个示例的比较函数的编写: ```c int compare(const void *a, const void *b) { int num1 = *((int *)a); int num2 = *((int *)b); return num1 - num2; } ``` 这个示例中的比较函数用于对整数数组进行升序排序。首先进行类型转换,将a和b转换为int类型的指针,然后取指针所指向的值,即得到实际的整数值。最后,使用减法操作符比较这两个整数的大小,得到比较结果。 总之,编写比较函数要注意函数原型、返回值、类型转换和比较实现等几个要点,根据实际需求编写相应的比较逻辑。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

罅隙`

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

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

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

打赏作者

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

抵扣说明:

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

余额充值