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