当前位置:首页 » 《资源分享》 » 正文

模拟实现qsort函数_莓关系的博客

27 人参与  2021年09月16日 17:03  分类 : 《资源分享》  评论

点击全文阅读


如何使用qort函数

首先需要引入头文件

#include <stdlib.h>
#include <search.h>

 让我们先来看看qsort函数都有哪些参数。

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

 

base:指向目标数组的指针。

num:数组中元素的个数,无符号数

width:数组中元素所占字节数,无符号数

int(_cdecl*compare)(const void *elem1,const void *elem2):

这个参数表示的是,一个函数指针。函数返回值为lin类型,有两个函数参数,都是void *类型的指针,它们表示的是,数组内两个进行比较的元素。

这里讲解一下,为什么base、elem1、elem2的类型都是void *。这是因为,qsort能都将各种类型的数组进行排序,在使用qsort函数并给它传入数组地址的时候,qsort不能确定接收某一个类型的地址,例如,如果把base的类型改为char *,那么当传入int类型的数组时,代码就会报错误。

void qsort( char *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

所以,使用void *来接收地址的好处就是,void *能够接受任何类型的地址,且不报错。我们只需要在函数内部,将void *类型的地址再转换成我们需要的类型就可以了。

elem1和elem2同理,这两个参数表示的意思是两个进行相比较的元素。当我们不知道用什么类型来接收的时候,就可以用void *来接收。

void *类型的指针有一个缺点,那就是该类型的指针不能够进行运算。

讲解完qsort函数需要有哪些参数了之后,接下来我们的主要工作就是编写比较两个数大小的函数。这里是对应qsort最后一个参数,函数指针。

compare函数的要求是,elem1大于elem2就返回一个正值,elem1小于elem2就返回一个负值,elem1等于elem2就返回一个0;

typedef struct student
{
	char name[20];
	int age;
}test;
//比较整型
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
//比较结构体中的name成员
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((test*)e1)->name, ((test*)e2)->name);
}
//比较结构体中的age成员
int cmp_by_age(const void* e1, const void* e2)
{
	return ((test*)e1)->age - ((test*)e2)->age;
}

接下来就可以使用qsort函数了。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <search.h>
//模拟实现qsort函数
//qsort函数的功能是利用冒泡排序法的原理,将各种类型的数据进行排序
typedef struct student
{
	char name[20];
	int age;
}test;
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((test*)e1)->name, ((test*)e2)->name);
}
int cmp_by_age(const void* e1, const void* e2)
{
	return ((test*)e1)->age - ((test*)e2)->age;
}
//整型数组测试函数
void test_int(int* arr_int, int sz)
{
	qsort(arr_int, sz, 4, cmp_int);
	//打印数组
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr_int[i]);
	}
	printf("\n");
}
//结构体数组测试函数
void test_struct(test* stu1, int sz)
{
	qsort(stu1, sz, sizeof(stu1[0]), cmp_by_age);//结构体按成员age排序
	for (int i = 0; i < sz; i++)
	{
		printf("%s ", stu1[i].name);
		printf("%d\n", stu1[i].age);
	}
}
int main()
{
	test s1[4] = { {"张三",18},{"李四",20},{"王五",30},{"盖伦",28} };
	int arr[] = { 5,6,1,2,4,7,8,3,9 };
	unsigned int len1 = sizeof(arr) / sizeof(arr[0]);
	unsigned int len2 = sizeof(s1) / sizeof(s1[0]);
	//测试使用qsort函数
	test_int(arr, len1);
	test_struct(s1, len2);
	return 0;
}

输出结果:

可以看出,整型数组已经按照从小到大的顺序排列好,结构体数组也已经按照成员age的大小排序好。按照成员name排序,只需要在给qsort函数传入参数的时候,将cmp_by_age换成cmp_by_name就可以了。

 我展示一下结构体按照成员name排序的输出结果。

 模拟实现qsort函数

主要是利用冒泡排序的方法进行排序。

这里主要讲解,函数内部两个数据是如何进行计较以及交换的。

void My_qsort(void* base, size_t num, size_t width, int(*cmp)(const void* elem1, const void* elem2))
{                                              //回调函数
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//if (cmp(elem1,elem2)>0)//如果返回值是0,表示元素1大于元素2,那么就进行交换
			//{
				//交换
			//}
		}
	}
}

问题在于,我们只得到了一个void *类型的数组地址,该如何确定出,这个数组中的元素呢?

毫无疑问,肯定需要先将void *类型的地址转换成其他的类型才可以进行运算。我们调用cmp函数的时候,我们只需要传入两个相邻数据地址即可,因为cmp函数内部会帮我们转换数据类型并进行比较。那么该如何找到两个相邻数据的地址呢?

可以将void *base转换成char *base,然后elem1和elem2的地址就可以表示成base和base+width

所以在上图的基础上,elem1的地址可以表示为 base + j * width,elem2的地址表示为base + (j + 1) * width。这表示,当第i趟j次比较的时候,元素elem1和elem2的地址。

接下来就是将两个数据进行交换

采用字节逐一交换的方法

void Swap(char* buf, int width)
{
	for (int i = 0; i < width; i++)
	{
		char tmp = *buf;
		*buf = *(buf + width);
		*(buf + width) = tmp;
		buf++;
	}
}

最后,模拟实现qsort函数就完成了,以下是代码展示。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <search.h>
//模拟实现qsort函数
//qsort函数的功能是利用冒泡排序法的原理,将各种类型的数据进行排序
//void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ));
typedef struct student
{
	char name[20];
	int age;
}test;
int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((test*)e1)->name, ((test*)e2)->name);
}
int cmp_by_age(const void* e1, const void* e2)
{
	return ((test*)e1)->age - ((test*)e2)->age;
}
void Swap(char* buf, int width)
{
	for (int i = 0; i < width; i++)
	{
		char tmp = *buf;
		*buf = *(buf + width);
		*(buf + width) = tmp;
		buf++;
	}
}
//升序
void My_qsort(void* base, size_t num, size_t width, int(*cmp)(const void* elem1, const void* elem2))
{                                              //回调函数
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0)//>0
			{
				Swap((char*)base + j * width, width);
			}
		}
	}
}
//整型数组测试函数
void test_int(int* arr_int, int sz)
{
	My_qsort(arr_int, sz, 4, cmp_int);
	//打印数组
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr_int[i]);
	}
	printf("\n");
}
void test_struct(test* stu1, int sz)
{
	My_qsort(stu1, sz, sizeof(stu1[0]), cmp_by_name);
	for (int i = 0; i < sz; i++)
	{
		printf("%s ", stu1[i].name);
		printf("%d\n", stu1[i].age);
	}
}
int main()
{
	test s1[4] = { {"张三",18},{"李四",20},{"王五",30},{"盖伦",28} };
	int arr[] = { 5,6,1,2,4,7,8,3,9 };
	unsigned int len1 = sizeof(arr) / sizeof(arr[0]);
	unsigned int len2 = sizeof(s1) / sizeof(s1[0]);
	//测试使用qsort函数
	test_int(arr, len1);
	test_struct(s1, len2);
	return 0;
}


点击全文阅读


本文链接:http://zhangshiyu.com/post/27928.html

函数  数组  类型  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1