关于qsort函数

2024-01-23 16:12:53 浏览数 (2)

路遥知马力,日久见人心。——元《争报恩》

1、qsort函数使用举例

代码语言:javascript复制
#include <stdio.h>  //qosrt函数的使⽤者得实现⼀个⽐较函数
int int_cmp(const void * p1, const void * p2)
{
 return (*( int *)p1 - *(int *) p2);
}
int main()
{
 int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
 int i = 0;
 qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
 for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i  )
 {
 printf( "%d ", arr[i]);
 }
 printf("n");
 return 0;
}

2、qsort函数具体的说明

链接: 可以自己搜索,得到的结果会更全面 根据网站,我们可以知道,qsort函数里面,需要用到的数值是这样的。

代码语言:javascript复制
void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

Sort elements of array//排列数组的顺序 Sorts the num elements of the array pointed to by base, each element size bytes long, using the compar function to determine the order.//默认更具byte来排序 The sorting algorithm used by this function compares pairs of elements by calling the specified compar function with pointers to them as argument. The function does not return any value, but modifies the content of the array pointed to by base reordering its elements as defined by compar.//该函数没有返回值,只是将数组进行了,排序。 那么根据上面介绍的内容,其实我们可以了解到,到底是为什么,qsort函数使用举例到底是什么意思。 在举例说明的qsort函数中。 第一个量,要说明来源的开始地址。 第二个量,要表述出,如果是一种类型,一个数组里面会有多少个(类型有很多,所以不能直接是sizeof(arr),因为不是所有类型都是1个字节) 第三个量,是表达出每一个数组里面的类型占多少的字节,即单个元素长度。(这里是为了,给以后的两个元素交换做准备。因为即使是4个字节的整型,也可以通过一个字节,一个字节的内容进行交换,把两个数值交换,知道当元素的字节,也会方便在后来进行交换。) 第四个量,就是要填上一个函数,为确保比较大小到底是按照什么样子来比较。(里面一定要把变量的void*改掉,不然计算的时候 1是不知道加上去多少的)

2、1void

2、1、1void是什么?

void是通用指针类型。也就是说,可以接受任意变量数据类型的地址可以接受任意数据类型地址,这样的目的其实也很明显,就是说为了qsort函数的正确使用,但是又不知道函数里面,别人会比什么类型,就有可能是,我要比较整型,但是你却要比较字符一样。这也的话,就可以让写的人能有更多的改变机会。比较不同类型的数据。

2、1、2void注意

如果你一不小心的使用了void函数的情况下,你还把*void了,那么恭喜你,你会出错,其实仔细想想,既然void都是通用的指针类型了,你解引用到底会出现什么呢?你要是问我,我当然不知道啊,你要问机器,他也不可能知道你void到底接受了什么啊。不会知道到底要解引用多少个字节的。所以,一定,一定要,记住在使用举例时的,int_cmp函数里面的内容(当然,在举例子时候,使用的是要比较int类型的)

3、qsort模拟实现

其实为了,更好的了解,理解qsort函数。那么我们来模拟实现一下吧! 其实qsort是冒泡排序的老大哥,因为冒泡排序是我们设置的只能排列整型数组的。下面请看冒泡排序,来回忆一下。

3、1、怀念冒泡排序

代码语言:javascript复制
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 - i - 1; j  )
		{
			if (arr[j] > arr[j   1])
			{
				int tmp = arr[j];
				arr[j] = arr[j   1];
				arr[j   1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	for (i = 0; i < sz; i  )
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

优化

代码语言:javascript复制
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{
	int i = 0;
	for (i = 0; i < sz - 1; i  )
	{
		int flag = 1;//假设这⼀趟已经有序了
		int j = 0;
		for (j = 0; j < sz - i - 1; j  )
		{
			if (arr[j] > arr[j   1])
			{
				flag = 0;//发⽣交换就说明,⽆序
				int tmp = arr[j];
				arr[j] = arr[j   1];
				arr[j   1] = tmp;
			}
		}
		if (flag == 1)//这⼀趟没交换就说明已经有序,后续⽆序排序了
			break;
	}
}
int main()
{
	int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	for (i = 0; i < sz; i  )
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

可以比较一下,加深一下回忆。 其实主要就是flag的作用,让没有意义的排序结束,尽快的进行下一轮。

3、2思考qsort模拟实现

首先要知道的是,qsort不只是像冒泡排序那样,排列整型,还要排列很多其他的类型。所以,先来完成比较简单的用来比较的函数

3、2、1int_cmp函数的实现
代码语言:javascript复制
int int_cmp(const void*p1,const void*p2)
{
    return (*(int *)p1-*(int *)p2)
}

当然,这里的将p1和p2,转化为int*还是其他的,都是可以的,按照想要实现的功能来设置。

3、2、2_swap函数的实现

_swap函数是为了将不符合大小顺序的元素进行交换,那么怎么样才能交换呢? 我们可以先想想,如果是整型的时候是怎么交换的? 其实就是,直接整型交换,但是我们现在模拟实现qsort函数的时候,不知道到底是什么类型,那该怎么进行交换呢? 其实,可以用char类型来进行辅助,因为char是最小字节,只占了1个字节,不管是什么类型都可以转化为1个字节,相互组合。 就好比是无论什么自然数,都可以通过1的叠加来表示出任何一个想要的数 所以,在函数的实现过程中,会输入除了地址的另外一个数,是用来告诉我们,到底一个元素是占多个字节。 下面再来看一下具体是怎么实现的,加深理解

代码语言:javascript复制
void _swap(void* p1, void* p2,int sz)
{
	int i = 0;
	for (i = 0; i < sz; i  )
	{
		char tmp = *((char*)p1   i);
		*((char*)p1   i) = *((char*)p2   i);
		*((char*)p2   i)=tmp;
	}
}
3、2、3类似冒泡排序函数的实现
代码语言:javascript复制
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < count - 1; i  )
	{
		for (j = 0; j < count - i - 1; j  )
		{
			if (cmp((char*)base   j * size, (char*)base   (j   1) * size) > 0)
			{
				_swap((char*)base   j * size, (char*)base   (j   1) * size, size);
			}
		}
	}
}

注意: (char *) base j * size(char *),就是根据不同类型来实现一个元素能和另一个元素实现交换,排序,是按照字节来进行对比,和交换。

3、3全部代码展示

代码语言:javascript复制
int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{
	int i = 0;
	for (i = 0; i < size; i  )
	{
		char tmp = *((char*)p1   i);
		*((char*)p1   i) = *((char*)p2   i);
		*((char*)p2   i) = tmp;
	}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < count - 1; i  )
	{
		for (j = 0; j < count - i - 1; j  )
		{
			if (cmp((char*)base   j * size, (char*)base   (j   1) * size) > 0)
			{
				_swap((char*)base   j * size, (char*)base   (j   1) * size, size);
			}
		}
	}
}
int main()
{
	int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	//char *arr[] = {"aaaa","dddd","cccc","bbbb"};
	int i = 0;
	bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i  )
	{
		printf("%d ", arr[i]);
	}
	printf("n");
	return 0;
}

0 人点赞