qsort的模拟实现

目录

 my_qsort的启程之路


        算法,是程序的灵魂。排序算法是典型的算法之一,我们初识c语言时,数组排序是一大难点。我们开始识得冒泡排序算法(bubble_sort)。但冒泡排序的缺点也很明显,那就是只能排序整形数组。


        那我们想一下,如果是字符数组呢?比如要比较abcdefg... 

        再深度思考一下,如果是结构体比较呢?比如要比较年龄,名字等等。

        要做到如上的排序实现,可以对冒泡排序进行一个优化,那就是库中的qsort函数。

        这个函数可牛了,什么类型都可以排序。让我们用一个专业网站查询一下吧!cplusplus.com - C++资源网络icon-default.png?t=M85Bhttps://legacy.cplusplus.com/  下图是qsort函数的参数及其功能

下图是qsort函数的应用实例

10 20 25 40 90 100

这样就用qsort成功排序好了一个整形数组。

 分析一下qsort函数的参数。站在一个设计师的角度,要排序一个用户需要的数组,那肯定要知道以下几点。我们来对它们分个工吧!

首先要注意引头文件<stdlib.h>

一. 既然是要排数组,那数组元素的地址就需要有一个指针来接收。void*base就负责存放待排序数据第一个对象的地址。

二. 有了数组的地址,排序数据元素的个数也必不可少,size_t num就负责统计和存放数组元素的个数。

前两点也是冒泡排序所需要的参数,那么接下来的参数,就是qsort独有的!

三. 因为bubble_sort专门针对整形数组,所以默认一个元素跳过一个整形(也就是4个字节)。但是如果是其他类型,则需要告诉函数一个数据元素的大小,由size_t size来统计和存放。

 四. 最后一个参数也是最难理解的部分。int (*compar) (const void *, const void *)首先它是一个函数指针,指向一个compar函数,这个函数是用来比较两个元素大小的函数,函数的参数是两个const void*——用指针来实现两个数据元素大小的比较,void*根据类型强制转换成想要排序类型的指针(比如例子中的强制转换成(int*))。int 是函数的返回值,两个元素比较,前大返回正数,前小返回负数。这样剖析会更好理解吧!

来排序一下结构体数据过过瘾吧! 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stu
{
	char name[20];
	int age;
};
int sort_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int main()
{
	struct stu s[3] = { {"zhangsan",30},{"lisi",31},{"wangwu",34} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), sort_by_name);
	return 0;
}

这样,我们对qsort的使用就了如执掌啦!当然,我们的目的在于模拟实现,也就是以开发者的角度在<stdlib.h>这个库中写入我们自己的qsort。如果清楚了怎么使用,自己写起来当然会更得心应手一些,当然也不是一件简单事,下面跟着我一起设计这个函数吧! 


 my_qsort的启程之路

 首先,参数无疑,模仿着qsort来即可。

把主函数写好,这里还是以整形数组为例。数组元素是我随便输入的,越随意测试效果越明显哈哈哈

int main()
{
	int arr[] = { 2, 51,63,723,8,12832,82,72,8 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, sz, sizeof(arr[0]), cmp);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

冒泡排序的趟数还是不变的,有变化的地方就是比较两个数据大小,也就是区别不同类型的地方,如下图标出来的①,②。 

 

 比较两个数据大小可就是一个难点了。如何判断两个数据的大小,如何实现两个数据的交换是我们要突破的。

我们第一个参数中拿到了数组首元素的地址,base指针指向了这个地址。

要比较前后两个数据的大小,是让指针+多少能表示一个元素的跨度呢?如上图,base指针类型是任意的,如果是整形指针,那么base+1就是跳过整形的一个数据,而char数组就是跳过4个数据。这样就不能达到比较大小的效果。那么我们应该怎么做呢?

既然最小的字节是1,那么不妨将base转换为char*的指针,然后根据元素的宽度进行base的加减。如下图:

cmp函数也就是我们自己根据数组类型写的比较大小的函数,如下图:

这样就圆满完成比较大小的任务啦!那么比较大小之后,肯定就是交换了。交换也是一种细活呢。

 

 我们写一个Swap函数来实现两个数据的交换。函数的参数跟cmp函数一样,但是多了个宽度。为什么呢?比较两个元素大小的话,只需要找到两个元素即可,如果要实现两个元素的交换的话,我们做不到。这时只需要将元素的每个字节都进行交换就能达到效果。如下图:

 

 我们可以将Swap函数这样写:

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++;
	}
}

这样我们的my_qsort函数就模拟实现完成啦!是不是很酷呢!来看看效果吧!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值