【C语言】qsort函数的实现和模拟运用

在介绍qsort这个神奇的函数之前,我想先介绍一个东西,叫冒泡排序,由此来引入一下

一、冒泡排序

而这个冒泡排序的核心思想就是:两两相邻的元素进行比较。(只能进行整型数据的排序

 下面给出代码:

void Change(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 tem = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tem;
			}
		}
	}
}

void 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,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Change(arr,sz);
	print(arr,sz);
	printf("\ncount=%d\n", count);
	return 0;
}

但我们发现这样做循环次数过多,所以我们可以进行改进,无序时我们在交换,原本就有序时不去交换

int count = 0;
void Change(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++)
		{
			count++;
			if (arr[j] > arr[j + 1])
			{
				flag = 0;//一旦无序,在进行交换,
				int tem = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tem;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}

void 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,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Change(arr,sz);
	print(arr,sz);
	printf("\ncount=%d\n", count);
	return 0;
}

如果大家还有什么更加好的方法,欢迎大家在评论区留言。接下来就让我们了解qsort吧

二、qsort函数

1.功能

qsort是C语言的一个库函数,用来对数据进行排序,(对任意数据都能进行排序)。

 这里第二个参数中提到的元素数就是你要排序的元素个数

这里的返回值意思就是假设有两个元素a与b,当a>b,返回值为一个大于0的数字;当a<b,返回值为一个小于0的数字;当a=b,返回值为一个等于0

注意:qsort函数的第四个参数是一个函数指针,其参数为void*类型,不能运算,根据需要进行迁至类型转换。

2.运用

(1)对整型排序

int cmp_int(const void* p1, const void* p2)
{
	if (*(int*)p1 > *(int*)p2)//强制类型转换成int*(4个字节,一个元素占4个字节)整形指针解引用,访问4个字节
	{                        //就是说*(int*)p1代表了一个整型元素进行比较
		return 1;
	}
	else
	{
		if (*(int*)p1 < *(int*)p2)
			return -1;
		else
			return 0;
	}
}

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

int main()
{
	test1();//用qsort()来排整型数组;
	return 0;
}

改进:对第四个参数的返回值进行改进(用表达式)


//第二中表示方法
//int cmp_int(const void* p1, const void* p2)
//{
//	return *(int*)p1 - *(int*)p2;
//}
//

(2)结构体排序,结构体中的种类繁多,有字符,有整型,所以我们可以通过两个方面来进行排序,其结果也会不同

  • 字符

    这里比较字符时需要一个函数是strcmp()(之后我会在字符函数中讲到),strcmp比较对应字符的ASCII码值,如:abcdef和abcdq相比q比e的ascii码值大,所以后者大于前者,同时其返回值也是极其巧妙的符合我们的qsort

 struct stu
{
	char name[20];
	int age;
};

//strcmp()是比较两个字符串的大小,比较对应字符的asc码值

int cmp_char_name(const void* p1, const void* p2)
{
	return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);//因为函数参数为void*类型,所以我们应该将其转换为struct stu*类型才能进行比较
    //test1()中的是比较的整型元素,所以我们将其转换成了int*类型
}

void test2()
{
	struct stu ch[] = {{"zhangsan",20},{"xiaoyan",18},{"wangwu",30}};//创建数组
	int sz = sizeof(ch) / sizeof(ch[0]);
	qsort(ch, sz, sizeof(ch[0]), cmp_char_name);
}

int main()
{
	test2();
	return 0;
}

  • 数字 
struct stu
{
	char name[20];
	int age;
};

int cmp_char_age(const void* p1, const void* p2)
{
	return ((struct stu*)p1)->age - ((struct stu*)p2)->age;//因为函数参数为void*类型,所以我们应该将其转换为struct stu*类型才能进行比较
    //test1()中的是比较的整型元素,所以我们将其转换成了int*类型
}

void test3()
{
	struct stu ch[] = {{"zhangsan",20},{"xiaoyan",18},{"wangwu",30}};//创建数组
	int sz = sizeof(ch) / sizeof(ch[0]);
	qsort(ch, sz, sizeof(ch[0]), cmp_char_age);
}

int main()
{
	test3();
	return 0;
}

(3)模拟实现 

我们这里通过排序整型进行模拟,当然后面我们也可以排序其他,这里只是用整型进行试验。

上面的两个代码因为是对整型排序,所以其返回值与qsort差不多

  因为我们是对qsort进行模拟,所以我们之后未来可能排序其他类型数据,因此模拟函数bubble_sort()的参数要类型与qsort高度一致

 而这里为什么要通过冒泡排序的形式呢,因为是一对一对字节进行比较的,接下来让小白详细给你们说说

 代码是:

if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0)//判断元素是否需要交换

那么判断完之后肯定要交换,这里我们不能像冒泡排序那样通过在创建一个变量进行交换,因为我们交换的肯定不只是整形数据。所以我们在创建一个函数执行,下面是我的一些思路,大家可以参考,同样如果有好的方法欢迎评论区留言,大家一起进步:

 

此时我们在创建一个char类型变量放第一个字节,然后以此类推通过循环向后遍历 :

void swap(char* bulf1, char* bulf2, size_t width)
{
	int i = 0;
	char tem = 0;
	for (i = 0; i < width; i++)//因为我们并不知道到底会传来什么样的数据,所以我们选择一个一个字节进行交换,判断
	{//所以我们选择char*类型的指针,因为它一次可访问一个字节。
		tem = *bulf1;
		*bulf1 = *bulf2;
		*bulf2 = tem;

		bulf1++;//实现一个一个字节访问
		bulf2++;
	}
}

通过以上分析,大致的模拟实现就结束了,这个模拟不仅可以实现整型的排序,还可以实现其他类型数据排序,下面是整个的代码,大家自行参考: 

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

void swap(char* bulf1, char* bulf2, size_t width)
{
	int i = 0;
	char tem = 0;
	for (i = 0; i < width; i++)//因为我们并不知道到底会传来什么样的数据,所以我们选择一个一个字节进行交换,判断
	{//所以我们选择char*类型的指针,因为它一次可访问一个字节。
		tem = *bulf1;
		*bulf1 = *bulf2;
		*bulf2 = tem;

		bulf1++;//实现一个一个字节访问
		bulf2++;
	}
}

int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}

void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{
	int i = 0;
	for (i = 0; i < sz - 1; i++)//i表示趟数
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)//每一趟元素之间的比较和次数
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0)//判断元素是否需要交换
			{//强制类型转换的原因是base是void类型,不能进行计算                   
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);//交换元素
			}
		}
	}
}

void test4()
{
	int arr[] = { 3,1,4,6,5,8,9,2,7,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr, sz);
}

int main()
{
	test4();//自定义一个函数,模仿qsort()
	return 0;
}

到这里今天的学习就结束了,内容很多,希望大家慢慢消化。感谢大家支持。

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言数组排序函数qsort是标准库函数,用于对数组进行排序。它的使用方法是通过传入一个比较函数来指定排序的规则。在给出的代码中,我们可以看到使用qsort函数对一个整型数组进行升序排序的例子。\[1\] 为了实现qsort函数的功能,我们可以使用一种较为简单的排序算法,比如冒泡排序算法来模拟实现一个具有排序数组、字符串、结构体等功能的bubble_sort函数。\[2\]这个函数的参数可以仿照qsort函数的参数,包括要排序的数组的起始地址、元素个数、每个元素的大小以及一个比较函数。\[3\] 具体实现bubble_sort函数函数体可以根据冒泡排序算法来编写,通过比较相邻的元素并交换位置来实现排序。排序的规则可以通过比较函数来指定,根据需要可以实现升序或降序排序。 总结起来,qsortC语言标准库中的数组排序函数,可以通过传入比较函数来指定排序规则。如果想要模拟实现类似功能的排序函数,可以使用一种简单的排序算法,比如冒泡排序,并根据需要实现相应的比较函数。 #### 引用[.reference_title] - *1* *2* *3* [【C语言qsort()函数详解:能给万物排序的神奇函数](https://blog.csdn.net/weixin_72357342/article/details/130628874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值