qsort函数的使用详解

引入

我们之前实现过一个冒泡排序函数,将传入的整型数组中的每个元素从小到大排序(升序)。冒泡排序的大致内容如下:

#include<stdio.h>

void bubble(int arr[], int sz)
{
	for (int i = 0;i < sz - 1;i++)
	{
		for (int j = 0;j < sz - i - 1;j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int a = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = a;
			}
		}
	}
}
void print(int arr[], int sz)
{
	for (int i = 0;i < sz;i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 3,1,5,4,7,9,8,2,6,0, };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz);
	print(arr,sz);
	return 0;
}

其中print也是自制的函数,用于打印整型数组的内容。

但是就仅仅是冒泡排序是不够的,因为此排序不能解决所有的排序问题。比如说我要对字符数组排序,对结构体进行排序,此排序都是做不到的。但是冒泡排序有我们可以借鉴的地方。冒泡排序的二重循环是可以应对任何排序问题的,都是一次大循环将最大的数送到最后面。

for (int i = 0;i < sz - 1;i++)
{
	for (int j = 0;j < sz - i - 1;j++)
	{
		
	}
}

但是循环内部的代码就无法使用。比如我要排序字符数组,就不可以用“>”"<""="">=""<="等符号,之前学过比较两个字符串的大小用的是strcmp函数,大于就返回正值,小于返回负值,等于返回0。所以具体的“比较”这个步骤不同的排序所要求的代码时不同的。

既然处理不同的排序问题,存在相同的部分,也有不同的步骤,那么我们是不是可以设计一个函数,这个函数用于处理一切的排序问题,它将两重循环,也就是相同的部分包装起来,至于不同的部分则需要我们给它传参数(函数指针),告诉它用什么样的方式排列。这就是我们今天讨论的中心,qsort函数(库函数)。

qsort函数

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

这是qsort的传参需要。其中void*base传入的是首元素的地址,size_t nitems传入的是元素的个数(size_t 是无符号整型类型),size_t size传入的是每个元素的大小,int (*compar)(const void *, const void*)是函数指针,它规定了此函数的返回类型与传参要求,是告诉qsort函数如何排序(当然这个函数要我们自己实现)。下面我们举几个例子。

1.字符指针的排序


#include<stdio.h>
#include<stdlib.h>//qsort函数需要的头文件
#include<string.h>//strcmp函数需要的头文件
void print(char arr[], int sz)//打印字符数组的函数
{
	for (int i = 0;i < sz;i++)
	{
		printf("%c ", arr[i]);
	}
}
int charfunc(const void*a, const void*b)
{
	//这里用到了strcmp函数,此函数要传入两个字符指针。
	int c = strcmp((char*)a, (char*)b);
	return c;
}
int main()
{
	char arr[7] = "bcdafe";
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sizeof(arr) / sizeof(arr[0]), 1, charfunc);
	print(arr, sz);
	return 0;
}

2.结构体的排序 (自定义学生类)

1.按年龄排序

struct stu
{
	char name[20];
	int age;
}; 
int agefunc(const void*a, const void*b)
{
	int c = ((struct stu*)a)->age - ((struct stu*)b)->age;
	return c;
	
}
int main()
{
	struct stu s[] = { {"wang",18},{"li",25},{"zhong",20} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), agefunc);
	
	return 0;
}

2.按名字排序

struct stu
{
	char name[20];
	int age;
}; 
int namefunc(const void* a, const void* b)
{
	int c = strcmp((char*)a, (char*)b);
	return c;
}
int main()
{
	struct stu s[] = { {"wang",18},{"li",25},{"zhong",20} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), namefunc);
	
	return 0;
}

自制qsort函数

我们接下来尝试自制my_sort函数。当然库函数qsort是用快速排序的方法实现的,我们这里就用冒泡排序的方法模拟实现。

void swap(void* a, void* b, int size)//实现交换的函数
{
	for (int i = 0;i < size;i++)
	{
		char c = *((char*)a + i);//特别注意,中间变量c的类型用char
		*((char*)a + i) = *((char*)b + i);
		*((char*)b + i) = c;



	}
}
//自制qsort函数my_sort
void my_sort(void* base, int sz, int size, int(*cmp)(const void(*a), const void(*b)))
{
	for (int i = 0;i < sz;i++)
	{
		for (int j = 0;j < i;j++)
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}
//定义结构体(学生)
struct stu
{
	char name[20];
	int age;
}; 


int agefunc(const void*a, const void*b)//按年龄排序的函数
{
	int c = ((struct stu*)a)->age - ((struct stu*)b)->age;
	return c;
	
}
int namefunc(const void* a, const void* b)//按名字排序的函数
{
	int c = strcmp((char*)a, (char*)b);
	return c;
}
int main()
{
	struct stu s[] = { {"wang",18},{"li",25},{"zhong",20} };
	int sz = sizeof(s) / sizeof(s[0]);
	my_sort(s, sz, sizeof(s[0]), namefunc);//检验自制my_sort函数
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值