0
点赞
收藏
分享

微信扫一扫

qsort函数的功能与实现思路

时光已翩然轻擦 2022-03-21 阅读 125
c语言

在对某些数据进行排序的时候,例如很简单的冒泡排序可以帮助我们实现整数的排列

那在对复杂情况进行排序时,C语言提供了一个很好用的函数qsort帮助我们进行排序

本文就qsort的功能及其实现进行讲解。

一、冒牌排序排列0 1 2 3 4 5 6 7 8 9

代码:

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

void bubble_sort(int arr[], int sz)
{
	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])
			{
				//交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

void test_by_bubble()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);
	print(arr, sz);
}

int main()
{
	//实现升序
	test_by_bubble();
}

我们上述所定义的函数,只能单一地实现对于整数的排序

观察C语言提供地qsort:

利用这个函数,我们可以试着排列一些复杂的数据,比如:结构体类型的数据:

 

 下边的年龄、成绩也可以排序:

 

 不难发现,qsort函数,确实可以排列较为复杂的数据。那就来分析,实现它。

二、分析qsort

回想上面的冒泡排序,我们传的参数为数组地址和一共排序多少个。

这里的qsort函数只是比刚才的冒泡排序多了

一个宽度(指出元素类型),一个比较规则(函数指针实现)

先上代码,再逐一解答:

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 my_qsort(void* base, int num, int width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//判断
			//if (arr[j] > arr[j + 1])
			if(cmp((char*)base+j*width, (char*)base + (j+1) * width) >0)		//cmp是函数指针,带回来一个int型的数据   >0 就交换
			{
				//交换
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

 

三、测试自己实现的my_qsort 

通过名字排序结构体:

通过年龄:

通过分数:

 附上代码:

#include<stdio.h>

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

void bubble_sort(int arr[], int sz)
{
	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])
			{
				//交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

void test_by_bubble()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);
	print(arr, sz);
}
//创建结构体数据类型进行排序
struct Stu
{
	char name[20];
	int age;
	double score;
};
//实现刚才的冒泡排序

//通过名字排序(现在为升序)
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

//通过年龄排序(现在为升序)
int cmp_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

//通过成绩排序(现在为升序)
int cmp_by_score(const void* e1, const void* e2)
{
	return (int)(((struct Stu*)e1)->score - ((struct Stu*)e2)->score);
}

void qsort_struct()
{
	struct Stu arr[3] = { {"zhangsan",15,100.0},{"lisi",25,80.0},{"wangwu",20,59.9} };
	int sz = sizeof(arr) / sizeof(arr[0]);

	qsort(arr, sz, sizeof(arr[0]), cmp_by_name);
	qsort(arr, sz, sizeof(arr[0]), cmp_by_age);
	qsort(arr, sz, sizeof(arr[0]), cmp_by_score);
}



//--------------------------------------------------------------------------------------------------------------------------------下面自己实现

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 my_qsort(void* base, int num, int width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//判断
			//if (arr[j] > arr[j + 1])
			if(cmp((char*)base+j*width, (char*)base + (j+1) * width) >0)		//cmp是函数指针,带回来一个int型的数据   >0 就交换
			{
				//交换
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

void my_qsort_struct_test()
{
	struct Stu arr[3] = { {"zhangsan",15,100.0},{"lisi",25,80.0},{"wangwu",20,59.9} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, sz, sizeof(arr[0]), cmp_by_name);
	my_qsort(arr, sz, sizeof(arr[0]), cmp_by_age);
	my_qsort(arr, sz, sizeof(arr[0]), cmp_by_score);
}


int main()
{
	//实现升序
	my_qsort_struct_test();
	return 0;
}

总结:

因为qsort可以对复杂类型的数据进行排序,所以它函数的形参类型为void*,在进行模拟实现时,要记得将其强制类型转化为char*再进行操作。

又因为以字节为操作,就需要多传一个形参width来记录比较的字节数

每次实现时默认都是升序的,如果需要降序排列,可将比较函数的返回值前后调换位置。

比如上述例子中,如果对年龄想要升序排列,可以将代码改为:

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

以上就是qsort函数的实现了。

举报

相关推荐

0 条评论