实现通用冒泡排序
我们在c语言的学习中都学过冒泡排序,但是我们的冒泡排序写成函数时往往有类型的限制,这就使我们今后的使用变得不够方便,所以想到实现一个通用的冒泡排序函数。
原理分析
在库函数中有一个通用的快速排序函数,我们思考他的参数设计,
并模仿设计出我们通用的的冒泡排序函数 bubble_sort
我们将他的函数参数拿出来看,在图中下方给出了每个参数的英文解释,我再解释一下其作用
void qsort( void *base,
size_t num,
size_t width,
int (__cdecl *compare )(const void *elem1, const void *elem2 )
);
- base需要排序的数组的数组名
- num数组元素个数(用来控制循环次数)
- width元素的宽度(单位字节) —— 作用因为元素种类的不同所以在交换元素时依靠一个字节一个字节的交换
- 最后的那一段是一个函数指针(因为不同的类型有不同的比较方法所以,需要提供比较方法的函数)
代码
bubble_sort
bubble_sort函数设计为:
void bubble_sort(void *base, int num, int width,
int (*cmp)(const void *e1, const void *e2))
{
for (int i=0; i<num-1; i++)
{
for (int j=0; j<num-i-1; j++)
{
if ((cmp((char*)base+j*width,(char*)base+(j+1)*width)>0))
{
Swap((char*)base+j*width, (char*)base+(j+1)*width, width); //Swap为交换函数
}
}
}
}
- 有必要解释一下的是交换函数比较函数中接受的两个参数
(char*)base+j*width 和 (char*)base+(j+1)*width) 我们比较比较两个值时 要找到这两个值,就要拿到这两个值的地址即一个数首字符的地址,然后交给比较函数,base即要比较的值的第一个字节地址,因为值类型的不同所以要找到下一个值的首地址,就要跳过他的宽度。 - 函数中为兼容所有类型指着为void*类型,我们操作时按那个字节操作所以强转为char*类型
Swap
继续写Swap
void Swap(char *p1,char *p2,int width)
{
for (int i=0; i<width; i++)
{
char tmp = *(p1+i);
*(p1+i) = *(p2+i);
*(p2+i) = tmp;
}
}
- 交换一对值时要按每个字节交换,所以width控制循环次数
cmp函数
这里就比较特殊了因为,不同类型的值比较方法不同这里我们只做出,int类型,double类型,结构体中的字符串类型。
更多的类型大家可自行扩充。
- 注意
函数都返回整形,第一个数大于第二的数返回大于零的整形数字,相等返回0,小于返回小于零的整形数字。
- int类型
int cmp_struct_name(const void *p1, const void *p2)
{
return strcmp((*(struct stu*)p1).name, (*(struct stu*)p2).name);
}
直接返回两个整形的差即可
2. double类型
int cmp_double(const void *p1, const void *p2)
{
if ((*(double*)p1 - *(double*)p2) >0)
{
return 1;
}
else if((*(double*)p1 - *(double*)p2) <0)
return -1;
else
return 0;
}
因为double类型相减有小数所以不能直接作为整形输出,稍作处理。
3. struct中的字符型
int cmp_struct_name(const void *p1, const void *p2)
{
return strcmp((*(struct stu*)p1).name, (*(struct stu*)p2).name);
}
stu是已经声名好的一个结构体
当你们声明别的结构体时记得换掉。
功能展示
整体代码:
#include <stdio.h>
#define SIZEOF(arr) sizeof(arr)/sizeof(arr[0])
struct stu
{
char name[10];
int age;
};
int cmp_int(const void *p1, const void *p2)
{
return *(int*)p1 - *(int*)p2;
}
int cmp_double(const void *p1, const void *p2)
{
if ((*(double*)p1 - *(double*)p2) >0)
{
return 1;
}
else
return 0;
}
int cmp_struct_name(const void *p1, const void *p2)
{
return strcmp((*(struct stu*)p1).name, (*(struct stu*)p2).name);
}
int cmp_struct_age(const void *p1, const void *p2)
{
return (*(struct stu*)p1).age - (*(struct stu*)p2).age;
}
void Swap(char *p1,char *p2,int width)
{
for (int i=0; i<width; i++)
{
char tmp = *(p1+i);
*(p1+i) = *(p2+i);
*(p2+i) = tmp;
}
}
void bubble_sort(void *base, int num, int width,
int (*cmp)(const void *e1, const void *e2))
{
for (int i=0; i<num-1; i++)
{
for (int j=0; j<num-i-1; j++)
{
if ((cmp((char*)base+j*width,(char*)base+(j+1)*width)>0))
{
Swap((char*)base+j*width, (char*)base+(j+1)*width, width);
}
}
}
}
int main()
{
struct stu stu[3] = {
{"liu",18},
{"app",20},
{"xiao",10}
};
int arr1[] = {2,3,5,4,6,7};
double arr2[] = {3.5, 4.2, 1.0, 8.8, 2.4};
bubble_sort(stu, SIZEOF(stu), sizeof(stu[0]), cmp_struct_age);
bubble_sort(arr1, SIZEOF(arr1), sizeof(arr1[0]), cmp_int);
bubble_sort(arr2, SIZEOF(arr2), sizeof(arr2[0]), cmp_double);
printf("结构体按名字排序\n");
for (int i=0; i<SIZEOF(stu); i++)
{
printf("%s\n",stu[i].name);
printf("%d\n",stu[i].age);
}
printf("int从小到大\n");
for (int i=0; i<SIZEOF(arr1); i++)
{
printf("%d ",arr1[i]);
}
printf("\n");
printf("double从小到大\n");
for (int i=0; i<SIZEOF(arr2); i++)
{
printf("%lf\n",arr2[i]);
}
return 0;
}
输出结果:
结构体按名字排序
name:xiao
age:10
name:liu
age:18
name:app
age:20
int从小到大
2 3 4 5 6 7
double从小到大
1.000000
2.400000
3.500000
4.200000
8.800000