c语言qsort函数的模拟详细过程(冒泡排序)

c语言模仿qsort函数构造能够处理各种类型数据的冒泡排序法函数

1、前言

新手第一次尝试写博客,有错还望大佬们指正!轻喷!

众所周知,在c语言学习中,基础的冒泡排序法只能够实现对int型数据的排序,代码如下:
#include<stdio.h>
int main()
{
	int a[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int i;
	//此循环为循环的趟数
	for (i = 0; i < 9; i++)
	{
		int j;
		//次循环为每趟循环进行交换位置的数据对数
		for (j = 0; j < 9 - i; j++)
		{
			if (a[j] > a[j + 1])
			{
				int temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}
		}
	}
	for (i = 0; i < 9; i++)
		printf("%d ", a[i]);
	return 0;
}
但是当我们把数组类型改为其他数据类型时,此冒泡排序方法便行不通了。

2、因此需要写一个函数 (命名为My_sort),来实现各种数据类型的冒泡排序法

首先编写main函数 ,通过test_int函数来进入例子(以int型为例,其他类型数据见后文)

#include<stdio.h>
int main()
{
	test_int();
	return 0;
}

因为test_int ( ) 函数不需要返回值,用void型即可。
这里传给My_sort函数的实参是根据qsort函数的参数类型编写的!

void test_int()
{
	int a[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(a) / sizeof(a[0]);
	My_sort(a, sz, sizeof(a[0]), cmp_int);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", a[i]);
	}
}

接下来是我们的核心函数My_sort,该函数的任务是将数据进行排序,同样不需要返回值,用void。

关于函数的各参数数据类型,分析如下:
void My_sort(void* base, int sz, int width, int (*cmp)(void* e1, void* e2))
{
	int i = 0;
	//排序趟数
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		//每趟排的次数
		for (j = 0; j < sz - 1 - i; j++)
		{
			//比较一对数的大小
			if (cmp_int((char*)base+j*width, (char*)base + (j+1) * width) > 0)
			{
				//交换两者位置
				Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}

首先需要一个指针*base来接收上一个函数传来的数据首元素的地址
sz是传来的数据中的元素个数
width是传来的数据的每个元素的字节数

void* base, int sz, int width

因为传来的是一个函数,所以这里用函数指针(指向函数的指针)。
因为判断时需要比较数的大小,需要一个返回值,当返回值>0,则需要交换,所以用int型返回。
那么为何函数的形参是void* 呢?
首先这个函数的作用是调换两个元素的值,必须得用指针才能将实参也改变。而因为传来的数据类型是不确定的(前面的数组a[10]虽然是int型,但只是一个例子)。

int (*cmp)(void* e1, void* e2)

接下来很关键!
我们的cmp函数的功能是将两数进行比较,当第一个数大于第二个数时,输出一个大于0的数,也就意味着需要将两个数交换数值。
函数的实参是:

(char*)base+j*width
(char*)base + (j+1) * width)

已知width是数据单个元素的字节数,而众所周知char型数据的大小是1字节。
所以这里将传来的首元素强制转换成char型,并加上j*width个字节。当j=0时,即表示第一个元素,当j=1时,即表示第二个元素,以此类推…
第二个实参同理。

if (cmp_int((char*)base+j*width, (char*)base + (j+1) * width) > 0)
			{
				//交换两者位置
				Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}

接着便要进入cmp函数了!
注意:cmp函数的功能是比较所给某个数据类型的两个数据的大小,若第一个数大,则返回一个大于0的值!
加const保证实参不会被改变。

int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

如果cmp_int函数返回了一个大于0的值,则需要将两个数进行交换,便进入Swap函数。
这和平常的swap函数不同,该函数的实参是char型,且传入了一个width(原数组每个元素的字节数),
于是通过以下代码,便可实现两个元素的交换!

void Swap(char* t1, char* t2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char temp;
		temp = *t1;
		*t1 = *t2;
		*t2 = temp;
		t1++;
		t2++;
	}
}

综上:便完成了可以使用冒泡排序法将int型数组排序的函数!

若要将其他类型的数据排序,只需将cmp_int函数改为对应的函数即可:
1、float型数据(double类型同理)

int cmp_float(const void*e1,const void*e2)
{
	if (*(float*)e1 == *(float*)e2)return 0;
	else if (*(float*)e1 > *(float*)e2)return 1;
	else if(*(float*)e1 < *(float*)e2)
	return -1;
}

2、结构体数据

struct stu
{
	char name[20];
	int age;
};
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
其他类型的数据都按照这个道理修改cmp函数即可完成!
内容概要:本文详细探讨了基于樽海鞘算法(SSA)优化的极限学习机(ELM)在回归预测任务中的应用,并与传统的BP神经网络、广义回归神经网络(GRNN)以及未优化的ELM进行了性能对比。首先介绍了ELM的基本原理,即通过随机生成输入层与隐藏层之间的连接权重及阈值,仅需计算输出权重即可快速完成训练。接着阐述了SSA的工作机制,利用樽海鞘群体觅食行为优化ELM的输入权重和隐藏层阈值,从而提高模型性能。随后分别给出了BP、GRNN、ELM和SSA-ELM的具体实现代码,并通过波士顿房价数据集和其他工业数据集验证了各模型的表现。结果显示,SSA-ELM在预测精度方面显著优于其他三种方法,尽管其训练时间较长,但在实际应用中仍具有明显优势。 适合人群:对机器学习尤其是回归预测感兴趣的科研人员和技术开发者,特别是那些希望深入了解ELM及其优化方法的人。 使用场景及目标:适用于需要高效、高精度回归预测的应用场景,如金融建模、工业数据分析等。主要目标是提供一种更为有效的回归预测解决方案,尤其是在处理大规模数据集时能够保持较高的预测精度。 其他说明:文中提供了详细的代码示例和性能对比图表,帮助读者更好地理解和复现实验结果。同时提醒使用者注意SSA参数的选择对模型性能的影响,建议进行参数敏感性分析以获得最佳效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值