qsort的模拟实现

目录

        1.什么是qsort函数

2.qsort函数的使用

3.模拟实现qsort函数

4.代码展示

1.什么是qsort函数


qsort函数是一种对数组进行排序的函数。 头文件为<stdlib.h>

1.2 qsort在程序中是如何设置的

一下是在cplusplus网站查找所得

这里我们可以看到qsort这个函数是有4给参数的,第一个参数void*base 是你需要他排序内容的起始位置,第二个参数是size_t的无符号整形:你要排序的大小是多少,第三个参数是size_t无符号的整形:你排序的每个变量的大小是多少,第四个参数是一个函数指针,该函数指针有2个参数,第一个参数是const void*类型的,第二个变量是const void*类型的返回值是int类型,他的返回类型是void类型。

当然他这些变量的定义是可以实现我排序任意类型的内容,

其中关于函数参数变量的解释可以在cplusplus中查到

2.qsort函数的使用

当然要想实现我们自己的qsort我们要先知道他是怎么使用的。

在上图中我们可以看到,在使用qsort的时候我们要传的内容分别是,你要排序内容的首地址,要排序多少个内容,每个要排序的变量的大小是多少,最后一个是,自己写一个函数去判断你每个内容的大小比较。

为了方便书写,我们这里使用结构体来进行演示

  struct Stu
{

	int age;
	char name[20];
};

struct Stu s[] = { {20,"zhangshan" },{19,"lisi"},{21,"wangwu"}};


我们在使用之前先定义一个结构体,里面定义三个内容,第一个是data,第二个是age,第三个是name,我们根据结构体去创建一个变量 及struct Stu s[ ],这里的s就是我们创建的变量。

在进行初始化时,我们给这个结构体赋予初值。

然后我们来用qsort进行排序

#include<stdio.h>
#include<stdlib.h>

 struct Stu
{
	int data[10];
	int age;
	char name[20];
};

//根据名字来比较
void imp_cmp_by_name(void* e1, void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

//根据年龄来比较
void imp_cmp_by_age(void* e1, void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int main()
{

	struct Stu s[] = { { 20,"zhangshan" },{19,"lisi"},{21,"wangwu"}};
	int sz = sizeof(s) / sizeof(s[0]);

	qsort(s, sz, sizeof(s[0]), imp_cmp_by_name);
	qsort(s, sz, sizeof(s[0]), imp_cmp_by_age);



	return 0;

}

这段代码中,sizeof(s[0]) 求的是一个结构体变量的大小是多少,

在这里面需要我们自己去写的是比较大小的函数

这里我们可以发现每一个比较函数的类型都被我定义成了俩个参数为都为 void*类型,返回值也是void*类型,,当然这里这样定义是为了跟qsort函数里面的函数指针类型保持一致,我们定义的函数在传递的时候要和接受该函数的指针类型保持一致。

当然一下这里我们需要主要的是void* 类型的指针是不能直接进行解引用的,我们需要将void*类型的指针强制类型转换成我们需要比较的类型即可,这里我是将void*类型的指针强制类型转化为struct Stu*类型的指针。

在书写比较函数时,我们也需要注意,这个还是要按照我们想要的排序大小来进行排序,返回的要是我们想要的值,及是返回 >0 还是返回 0 < 。

下面向大家展示不同排序后的结果

按照name排序前

排序后

在按照age来进行一次排序

可以看到内容都在根据我们的想法在进行排序

3.模拟实现qsort函数

这里我们就已经了解了qsort的实现原理那么接下来我们就要进行模拟实现qsort函数了

首先我们要从一个简单的排序来进行

int main()
{
    //创建结构体变量,进行初始化
	struct Stu s[] = { {"zhangsan",20,123456789104},{"lisi",19,236548946517},{"wangwu",21,981521321561} };
    //算出有多少个元素
	int sz = sizeof(s) / sizeof(s[0]);
    //按照name排序
	my_qsort(s,sz,sizeof(s[0]),imp_by_name);
    //按照age排序
	my_qsort(s, sz, sizeof(s[0]), imp_by_age);
 

	printf("\n");


	return 0;
}

在进行排序之前我们已经明白了qsort需要的基本参数,我们先把我们想怎么样去排序,先写好,然后在写上不同排序如何比较及实现自定义函数imp_by_name,imp_by_age。

//按照name来比较
void imp_by_name(void* e1,void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照age来比较
void imp_by_age(void* e1,void* e2)
{
	return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}

上述代码就是我们想要他按照从小到大的顺序去排序

然后我们,要来实现我们my_qsort的主题内容

void my_qsort(void* base, size_t num, size_t size,int (*cmp)(const void*, const void*))
{
	size_t i = 0;
	int flag = 1;
	for (i = 0; i < num;i++)
	{
		flag = 1;
		size_t j = 0;
		for (j = 0; j < num - 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);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}

可以看到,函数内部的内容就是我们所熟知的冒泡排序,但是同意的是,我们要排序的内容是用void*类型的指针去接收的,这里我们就能发现一些问题,当我们要去比较的时候,我们传的参数是不能直接解引用传递的,所以我们需要把他们都强制类型转换成char*类型的指针,因为char*类型的指针一次只能访问一个字节的空间大小,然后我们在给他加上,他原本一个类型的大小进行访问,就能一次访问该变量。然后根据我们传递的函数,按照我们想要结果去比较,如果满足我们的函数条件,进行排序,当然因为我们是用void*类型的指针来接收的,那个交换变量就需要将这俩个要交换内容的地址传递过去,在传递每个变量的大小是多少,进行交换

void Swap(void* e1, void*e2,int wide)
{
	char temp;

	while (wide)
	{
		temp = *(char*)e1;
		*(char*)e1 = *(char*)e2;
		*(char*)e2 = temp;
		e2 = (char*)e2 + 1;
		e1 = (char*)e1 + 1;
		wide--;
	}
}

当然,在交换时,我们是用void*类型的指针来接收的,因为这样我们就能交换各种类型的变量,在交换前,我们需要将void*类型的指针强制类型转换成char*类型的指针,因为char*类型的指针解引用一次只访问一个字节的大小。在交换之后我们也需要主要,void*类型的指针是不能直接进行加减操作的,我们在加减之前也是要进行类型转换的。

写到这里我们将我们写的内容组合一下qsort函数就被我们完成了

下面是代码的运行

按照name排序

按照age排序

4.代码展示

#include<stdio.h>
#include<stdlib.h>

struct Stu
{
	char name[20];
	int age;
};
//按照name来比较
void imp_by_name(void* e1,void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照age来比较
void imp_by_age(void* e1,void* e2)
{
	return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}


void Swap(void* e1, void*e2,int wide)
{
	char temp;

	while (wide)
	{
		temp = *(char*)e1;
		*(char*)e1 = *(char*)e2;
		*(char*)e2 = temp;
		e2 = (char*)e2 + 1;
		e1 = (char*)e1 + 1;
		wide--;
	}
}

void my_qsort(void* base, size_t num, size_t size,int (*cmp)(const void*, const void*))
{
	size_t i = 0;
	int flag = 1;
	for (i = 0; i < num;i++)
	{
		flag = 1;
		size_t j = 0;
		for (j = 0; j < num - 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);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}
int main()
{
	struct Stu s[] = { {"zhangsan",20},{"lisi",19},{"wangwu",21} };

	int sz = sizeof(s) / sizeof(s[0]);

	my_qsort(s,sz,sizeof(s[0]),imp_by_name);

	my_qsort(s, sz, sizeof(s[0]), imp_by_age);

	return 0;
}

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值