C语言:指针4(超级详细讲解qsort函数使用)

目录

​编辑

回调函数

qsort函数

qsort函数的使用

qsort排序整行

qsort结构体排序

结构体姓名排序(字符串排序)

结构体年龄排序(整行排序)

模拟qsort函数

比较函数

交换函数


回调函数

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

回调函数在指针3的转移表我们就用到了回调函数

回调函数是就一个函数

下面在代码我们可以看到,把add函数的地址传给了p函数,p用函数指针接收命名为x,

然后可以通过x把a和b的数值传过去给add,然后返回值给 r 然后打印

x里存放的是add函数的地址

这就是一个回调函数


qsort函数

下面是冒泡排序,冒泡排序只能排序整形,无法排序浮点和字符还有结构体,我们就

需要用到qsort函数来进行排序

 //冒泡排序
void add(int arr[], int sz)
{
    for (int i = 0; i < sz-1; i++)
    {
        for (int j = 0; j < sz - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                int r = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = r;

            }
        }
    }
 }

int main()
{
    int arr[] = { 2,4,6,8,10,1,3,5,7,9 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    add(arr, sz);
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }

 }

qsort函数的使用

qsort函数我们需要传4个参数(指向数组第1个元素的指针(首元素),元素个数值,元素类型大小,比较函数)

比较函数的参数为什么使用void*类型呢,因为void*可以接收全部参数,,但是比较数值必须要强制类型转换。

比较这2个数值的时候,(第1个值比第2个值大就返回大于0的数字(1))(第1个值比第2个小就返回小于0的数字(-1))(第1个值等于第2个值返回0)

返回大于1的话就交换这2个数值,小于等于不交换


qsort排序整行

整行排序我们可以使用减法

返回数值这个函数,为什么要用减法呢

因为x如果大于y,x减y的话就会得到大于0的数字

如果x小于y,x减y就会得到小于0的数值,

等于的话x减y就是0了

//返回数值
int add(const void* x, const void* y)
{
	return *(int*)x - *(int*)y;
}
int main()
{
	//要排序的数组
	int arr[] = { 2,4,6,8,10,1,3,5,7,9 };
	//计算元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	//qsort函数
	qsort(arr, sz, sizeof(arr[0]), add);
	//打印
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}

当然也可以这样写

//返回数值
int add(const void* x, const void* y)
{
	//大于
	if (*(int*)x > *(int*)y)
	{
		return 1;
	}
	//小于
	else if (*(int*)x < *(int*)y)
	{
		
		return -1;
	}
	//等于
	else
	{
		return 0;
	}
}
int main()
{
	//要排序的数组
	int arr[] = { 2,4,6,8,10,1,3,5,7,9 };
	//计算元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	//qsort函数
	qsort(arr, sz, sizeof(arr[0]), add);
	//打印
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}

qsort结构体排序
结构体姓名排序(字符串排序)


结构体年龄排序(整行排序)

这个可以和整行使用减法

//结构体
struct xs
{
	//姓名
	char xm[20];
	//年龄
	int nl;
};
//int add(const void* x, const void* y)
//{
//	//按姓名来排序
//	return strcmp(((struct xs*)x)->xm,((struct xs *)y)->xm);
//}

int add(const void* x, const void* y)
{
	//按年龄来排序
	return ((struct xs*)x)->nl  -  ((struct xs*)y)->nl;
}

int main()
{
	struct xs arr[3] = { {"zhangsan",15} ,{"lisi",25},{"xiaomin",22} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), add);
	for (int i=0; i < sz; i++)
	{
		printf("%s\n%d\n", arr[i].xm,arr[i].nl);
	}
}

模拟qsort函数

main函数还是和用来一样,来看模拟qsort函数


mn_qsort函数接收了4个参数,有2个无符号整行size_t,

2个for循环比较2个数值,和冒泡排序一样

b i j函数把 (char*)arr + j * f 和 (char*)arr + ( j + 1 ) * f 传给比较函数进行比较,大于0就交换

比较这2个数值的时候,(第1个值比第2个值大就返回大于0的数字(1))(第1个值比第2个小就返回小于0的数字(-1))(第 1个值等于第2个值返回0)

返回大于1的话就交换这2个数值,小于等于不交换


比较函数


交换函数

因为这是通用的交换方法,我们需要用char类型的指针进行交换,

为什么不用int指针类型的呢,因为如果用int的话,加1跳过4个字节,我们交换char类型的时候,char是1个字节,如果我们用int就会跳4个字节,所以我们要用char指针类型的

size_f是类型大小,这数组是int指针类型的我们就需要循环4次

//比较函数
int fh(const void*x,const void*y)
{
	//强制类型转换成char*然后解引⽤
	return (*(char*)x) - (*(char*)y);
}


//交换函数
int jh(char* x, char* y,size_t f)
{
	for (int i = 0; i < f; i++)
	{
		char r = *x;
		*x = *y;
		*y = r;
		x++;
		y++;
	}
}
//    数组首元素地址,元素个数,  类型大小      比较函数
void mn_qsort(void* arr[], size_t sz, size_t f, int(*bij)(int*, int*))
{
	//循环比较2个数值和冒泡排序一样
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - 1 - i; j++)
		{
			//             传参给比较函数                   判断是不是大于0
			if (bij((char*)arr + j * f, (char*)arr + (j + 1) * f) > 0)
			{
				//大于0,传参给交换函数                         类型大小
				jh((char*)arr + j * f, (char*)arr + (j + 1) * f, f);
			}
		}
	}
}
int main()
{
	int arr[] = { 2,4,6,8,10,1,3,5,7,9 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//模拟实现qsort函数
	mn_qsort(arr, sz, sizeof(arr[0]), fh);
	//打印
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[0] + i);
	}
}

  • 41
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值