qsort函数




介绍qsort函数之前,我们先了解一下什么是回调函数??

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

接下来介绍一下qsort函数

1.编译器函数库自带的快速排序函数。

2.使用qsort()排序并用 bsearch()搜索是一个比较常用的组合,使用方便快捷。

3.qsort 的函数原型是:void qsort(void*base, size_t num, size_t width, int(__cdecl*compare)(const void*, const void*));

各参数:1 待排序数组首地址 ;2 数组中待排序元素数量 ;3 各元素的占用空间大小; 4 指向函数的指针(待定函数的比较方法)

int(__cdecl*compare)()就是回调函数,将函数本身作为参数传递给对应的方法,然后在特定的时候再调用。


现在我们模仿qsort的功能实现一个通用的冒泡排序:


#include<stdio.h>
#include<windows.h>
#include<assert.h>

//回调函数
int int_cmp(const void *p1, const void *p2)
{
	int *_p1 = (int *)p1;
	int *_p2 = (int *)p2;
	
	if (*_p1 < *_p2)
	{
		return 1;//降序
	}
	else if (*_p1 > *_p2)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

//交换
void swap(char *x, char *y, int width)
{
	while (width--)
	{
		*x^=*y;
		*y^=*x;
		*x^=*y;
		x++;
		y++;
	}
}
//实现qsort
void my_qsort(void *arr, int num, int width, int(*cmp)(void *, void *))
{
	assert(arr);
	assert(cmp);

	int i = 0;
	for (; i < num - 1; i++)
	{
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//调用函数判断两个操作数大小。 
		    //cmp()传参只需将操作数的地址传过去。

			if (cmp((char *)arr + j*width, (char *)arr + (j + 1)*width)>0)

			//这里是任意类型,所以不能整体交换,只能局部按字节交换,达到整体交换的目的。
			{
				swap((char *)arr + j*width, (char *)arr + (j + 1)*width, width);
			}
		}
	}


}
int main()
{
	int arr[] = { 1, 5, 4, 6, 8, 0, 9, 2, 7, 3 };
	int size = sizeof(arr) / sizeof(arr[0]);
	int i = 0;

	my_qsort(arr, size, sizeof(int), int_cmp);
	for (i = 0; i < size; i++)
	{
		printf("%d\n", arr[i]);//9876543210
	}

	system("pause");
	return 0;
}

通过上面模拟实现我们了解到qsort能够进行排序,接下来我们来练习使用qsort函数排序各种类型的数据。

1.int 类型:
int int_cmp(const void *p1, const void *p2)
{
	int *_p1 = (int *)p1;
	int *_p2 = (int *)p2;

	if (*_p1 < *_p2)
	{
		return 1;//降序
	}
	else if (*_p1 > *_p2)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	int arr[] = { 1, 5, 4, 6, 8, 0, 9, 2, 7, 3 };
	int size = sizeof(arr) / sizeof(arr[0]);
	int i = 0;

	qsort(arr, size, sizeof(int), int_cmp);
	for (i = 0; i < size; i++)
	{
		printf("%d\n", arr[i]);//9876543210
	}

	system("pause");
	return 0;
}

//2.double类型:
int double_cmp(const void *p1, const void *p2)
{
	double *_p1 = (double *)p1;
	double *_p2 = (double *)p2;

	if (*_p1 < *_p2)
	{
		return -1;//升序
	}
	else if (*_p1 > *_p2)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	double arr[] = { 10.3, 5.0, 4.345, 6.66, 8.9, 0.1, 9.4, 2.5, 7.35, 3.09 };
	int size = sizeof(arr) / sizeof(arr[0]);
	int i = 0;

	qsort(arr, size, sizeof(double), double_cmp);
	for (i = 0; i < size; i++)
	{
		printf("%f  ", arr[i]);
	}
//0.100000  2.500000  3.090000  4.345000  5.000000  6.660000  7.350000  8.900000 9.400000  10.300000  请按任意键继续. . .
	system("pause");
	return 0;
}

//3.排序字符char类型:
int char_cmp(const void *p1, const void *p2)
{
	char *_p1 = (char *)p1;
	char *_p2 = (char *)p2;

	if (*_p1 < *_p2)
	{
		return -1;//升序
	}
	else if (*_p1 > *_p2)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	char arr[] = { 'v','A','g','t','H','M','d' };
	int size = sizeof(arr) / sizeof(arr[0]);
	int i = 0;

	qsort(arr, size, sizeof(char), char_cmp);
	for (i = 0; i < size; i++)
	{
		printf("%c  ", arr[i]);
	}
	//A  H  M  d  g  t  v  请按任意键继续. . .
	system("pause");
	return 0;
}

注意字符串传参问题: 因为char*是字符数组,后面跟的相当于字符数组名,而指向字符数组(字符串)的指针,那就再加一星号,char**就是指向字符数组的指针了(当然它也可以表示字符串数组)。函数定义时使用char **s1和char **s2作参数,函数内容不需要变。
使用这两个形参后,在函数体中,*s1表示指针s1指向的字符数组(字符串),*s2表示指针s2指向的字符数组(字符串),因此,函数体不需要做改变。



 


猜你喜欢

转载自blog.csdn.net/snowyuuu/article/details/80411036