ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

初步认识qsort函数以及利用冒泡排序进行初步模拟

2022-03-19 21:06:03  阅读:153  来源: 互联网

标签:sz arr int void qsort 冒泡排序 初步 width char


 

首先初步认识一下

qsort 是一个库函数,包含在头文件stdlib.h中

作用:基于快速排序算法实现的一个排序函数

接下来认识这个函数所需要的参数有四个。接下来分别进行分析。

首先我们发现数据起始位置的指针用的是void*来接受,为啥呢???

因为我们不知道我们将来比较的数据类型为什么,有可能是int*  或者char*  又或者是结构体指针,所以我们在这放置了一个void*来接受,void*可理解为通用类型指针,可能就有人问了,既然有这个万金油的指针类型,那我们还要其他指针类型干什么??下面给出了原因。

我们发现我们自己需要定义一个比较函数,参数类型为两个指针变量,返回类型为int  。

但是为什么这里的指针类型需要定义为void* 类型呢???

这里就需要我们明白指针类型的意义。

指针类型其实决定了,对指针解引用的时候有多大的权限(能操作几个字节)。

void*  可以接受任意类型的指针,但是确定也比较明显,就是在对指针解引用操作的时候,计算机不知道它有多大的权限(可以向后访问几个字节)。

由于我们并不知道我们所要比较的元素是哪种类型的,就采用空类型来接受。而在比较的时候,我们需要将其强制转化成比较的类型,方可进行比较。具体请看下面代码展示。

 对这个函数有一个初步了解之后,我们开始尝试使用这个函数。

int cmp_int(const void* e1, const void* e2)
{
	if (*(int*)e1 > *(int*)e2)
		return 1;
	else if (*(int*)e1 < *(int*)e2)
		return -1;
	else
		return 0;
	//return *(int*)e1 - *(int*)e2;
    //这种方式其实更好,利用前者减去后者,差返回就好。
    //这样刚好满足这个函数的定义
    //e1>e2 返回 大于0 <==>  e1-e2>0
    //e1<e2 返回 小于0 <==>  e1-e2<0
    //e1=e2 返回    0 <==>  e1-e2=0

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

int main()
{
	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	my_print(arr, sz);

	return 0;
}

在这个过程中,我们需要比较的是int类型的元素,故将额e1和e2强制类型转换成int* 。 

然后我们用qsort函数排序一下结构体。

int cmp_stu_by_age(const void* e1, const void* e2)
{
 	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test3()
{
	struct Stu arr[3] = { {"zhangsan", 20, 55.5},{"lisi", 30, 88.0},{"wangwu", 10, 90.0} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}
int main()
{
	test3();
	
	return 0;
}

经过排序后的结果如下图:

 我们发现年龄有原来的无序变为升序。

可以得出一个结论:利用qsort函数可以将一个无序的元素变为升序。那这里有人好奇了,那怎样才能变为降序呢???

其实我们只需要改变逻辑即可!原来我们创建了一个比较函数,其逻辑为

 我们颠倒逻辑改为 

 这样原来是升序,逻辑转换一下,就变为将序了。

经过前面的解析,已经初步明白了qsort函数的使用,我们发现qsort可以排列各种类型的数据,

那我们可以使用冒泡排序进行一个模拟,使我们的冒泡排序也可以万能呢?

首先观察一下我们原有的冒泡排序

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 print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz =  sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	print_arr(arr,sz);
	return 0;
}

发现要使冒泡排序可以排序任何元素,要进行一些改动。

 经过初步的分析,我们发现我们的冒泡排序还缺少某些参数。例如每个元素的宽度,如若知道这个整体的起始地址,再知道每个元素的宽度和元素的个数。

我们注意到,一旦冒泡排序的元素个数确定了,冒泡排序的趟数也就确定了。

其次,我们发现不同元素之间的比较方式不同,所以我们应该将比较方式提取出来,不同的数据类型采用不同的比较方式。所以就个人自行定义比较方式。

所以我们 的冒泡排序的整体大致为

void bubble_sort(void* base, int num, int width, int (*cmp)(const void*e1, const void*e2))

//base为数据的起始地址
//num为元素的个数
//width为每个元素的大小(字节)
//cpm为比较函数

由于我们无法提前得知比较类型的数据,故我们的比较函数的指针类型也应该为void*,以便存放各种类型的指针。

开始模拟

先写出整体的大致思路,然后进行修改。


//冒泡排序
void my_qsort(void* base, int num, int width, int(*com_int)(const void* e1, const void* e2))
{
	
	
		int i = 0;
		int j = 0;
		for (i = 0; i < num - 1; i++)
		{
			for (j = 0; j < num - 1 - i; j++)
			{
				/*
                 *if(>0)
                 *swap
                 *
                 *这里就是需要我们进行改变的。
                 *
                 */
			}
		}
	
}

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

我们思考如何应该如何让判断当前两个元素的大小???

先写出我们的一个比较函数

 首先观察我们原来的比较函数,如若前者大于后者,则进行交换。

类比与这个,我们可以写出


//比较函数
int com_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

 

 如果cmp-int(,)大于0,则前面的数据大于后面的数据,则进行交换。

 如果cmp-int(,)小于或者等于0,则前面的数据小于后面的数据,则不进行交换。

 

if(cmp(,)>0)
{
    //交换;
}

我们发现这个比较函数需要那两个待比较元素的首地址,可是我们该如何拿到这两个元素的首地址呢????

我们需要计算出待比较元素的地址

如何计算呢??

我们以整形数组为例进行演示:

 那么如何寻找相邻的待比较元素的地址呢??

再看一下这张图,我们来分析一下。其实这个过程中,相邻元素的下表一个是就 j ,一个是 j+1 。

//arr[j] <==>(char*)base + width*j
//arr[j+1] <==>(char*)base + width*(j+1)

所以判断函数可以写成

if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				
				/*
                 *
                 * 此处是交换函数;
                 * 
                 */
			}

现在我们来编写交换函数swap

首先交换函数需要传输  待交换元素的地址  , 如果传输   待交换元素的值     ,无法达到交换的效果。但是需要注意的是我们传输过去的是一个元素的首地址(char*),但是我们不知道一个元素有几个字节(就是一个元素的宽度)?我们知道,交换元素意味着元素的整体都进行交换,而不能只交换部分。故我们也应该将宽度(大小)传过去。

if (com_int((char*)a + j * width, (char*)a + (j + 1) * width)>0)
				{
					swap((char*)a + j * width, (char*)a + (j + 1) * width, width);

				}

以整形举例,方便大家理解这个交换过程。

由于 swap的参数类型为cahr* 类型,一次只能交换一个字节,故需要交换width(即元素的宽度或者大小)次 。故函数可以写为:

void swap(char* p1,char*p2,int width)
{
	for (int n = 0; n < width; n++)
	{
		char tmp = *(p1 + n);
		*(p1 + n) = *(p2 + n);
		*(p2 + n) = tmp;

	}
}

 通过单个字节的交换,实现元素的交换。

最终实现了利用冒泡排序实现qsort万能排序的功能。整体代码在下

//比较函数
int com_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

void swap(char* p1,char*p2,int width)
{
	for (int n = 0; n < width; n++)
	{
		char tmp = *(p1 + n);
		*(p1 + n) = *(p2 + n);
		*(p2 + n) = tmp;

	}
}
void my_qsort(void* base, int num, int width, int(*com_int)(const void* e1, const void* e2))
{
	
	
		int i = 0;
		int j = 0;
		for (i = 0; i < num - 1; i++)
		{
			for (j = 0; j < num - 1 - i; j++)
			{
				
				if (com_int((char*)a + j * width, (char*)a + (j + 1) * width)>0)
				{
					swap((char*)a + j * width, (char*)a + (j + 1) * width, width);

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

标签:sz,arr,int,void,qsort,冒泡排序,初步,width,char
来源: https://blog.csdn.net/m0_63711643/article/details/123595642

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有