前言:一般简单的冒泡排序只能进行一种数据类型的升序或者降序,而如果对其他的数据类型的数据进行排序的话会改动许多地方,由此看来不是很方便,那有没有一种简单的方法?c中有一个库函数qsort(void* base, size_t num, size_t size, int(*pf)(const void* p1, const void* p2)),它可以进行任意数据类型的排序,我们可以模仿该函数对任意数据类型的数据进行排序!
ps:字符串的排序是按首字母的ASCII值来进行排序,如果相等,则往后看在进行排序
1.主函数部分:
按照结构体中的姓名来排序:
//创建一个结构体,按照姓名来排序
struct Stu
{
char name[20];
int age;
};
void test1()
{
struct Stu arr[4] = { {"zhangsan", 15}, {"lisi", 20}, {"wangwu", 16}, {"baimou", 21} };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz, sizeof(arr[0]), cmp_str_by_name); //按结构体中的姓名来排序
//bubble_sort(arr, sz, sizeof(arr[0]), cmp_str_by_age); // 按结构体中的年龄来排序
}
int main()
{
test1();
return 0;
}
2.冒泡排序:
void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* p1, const void* p2))
{
int i = 0;
for (i = 0; i < num - 1; i++)
{
for (int j = 0; j < num - 1 - i; j++)
{
if (cmp((char*)base + width * j, (char*)base + width * (j + 1)) > 0)
{
Swap(((char*)base + width * j), (char*)base + width * (j + 1), width);
}
}
}
}
解释1:
bubble_sort中的第一个参数:待排序数组的首元素地址
第二个参数:待排序数组的元素个数
第三个参数:待排序数组中每个元素的大小
第四个参数:是一个函数指针,指向两个元素的比较函数(可以是整数比价,也可以是字符比较)
解释2:
cmp是一个指针,指向的是cmp_str_by_name函数。在传参是传的是一个(char*)指针,因为不确定数据类型,用 char* 来作为参数的话,在解引用的时候只会解引用一个字节,所以在这里还需要加上数据的大小,比如:
用此方法进行传参就可以传进任意数据类型的数据,Swap函数的参数同上
3.比较函数:(cmp_str_by_name,cmp_str_by_age等等)
//是什么类型的数据就转换成什么类型的数据
int cmp_str_by_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
int cmp_str_by_age(const void* p1, const void* p2)
{
return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
int cmp_int(const void* p1, const void* p2)
{
return *((int*)p1) - *((int*)p2);
}
用const void* p来接收是为了能够接收任意数据类型的数据,如果是字符串进行比较,需要用到strcmp函数(库函数为#include <string.h>,返回值类型为int:大于0(只有大于的时候才进行交换,对整形数据进行交换的时候也一样),等于0,小于0)
4.Swap函数:
void Swap(char* p1, char* p2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
解释:这里传参width的目的是为了对一个数据中的每一个字节与另一个数据中的每一个字节进行交换,这样以后任意数据类型的数据都可通过该函数进行交换了。
5.效果运行:
按照结构体中的姓名来排序:(这里只用到了调试来观察是否进行了排序)