仿照库函数qsort(),来实现一个通用的冒泡排序
qsort()是快速排序,库函数中的qsort()能对多种类型进行排序。
为了使冒泡排序也能对多种类型排序,我们首先需要了解一下qsort()的各项参数:
void qsort(void *base, size_t num, size_t width, int(__cdecl *compare)(const void *elem1, const void *elem2)
- void *base:表示要排序目标的起始位置
- size_t num:表示要排序元素的个数
size_t width: 表示每个元素的所占长度,单位是字节。 因为并不知道要排序的元素类型(字符串,数字或是其他),所以当第一次比较完之后,无法定位到下一次应该比较哪个位置的元素,所以很有比较知道
每个元素的长度,每次跳过该长度就能来到下一个元素的位置,比如整型,每次跳过4字节,来到下一个元素,结构体,每次跳过结构体中的元素的长度,便能指向下一个结构体元素。int(__cdecl *compare)(const void *elem1, const void *elem2): 是个函数指针,由于元素类型决定了元素之间的比较方式(字符串用strcmp()比较,数字可以直接比较),而函数库的设计者并不能知道
用户要比较什么类型的元素,所以这一部分需要由用户来设计函数,使用时通过函数指针调用用户所编写的函数冒泡排序函数中的参数参照上面。
通用冒泡排序代码:
#include<stdlib.h>
#include<string.h>
#include<assert.h>
struct stu
{
char name[20];
int age;
};
int cmp_int(const void *e1, const void *e2) //按照整型大小排序
{
return *(int *)e1 - *(int *)e2;
}
int cmp_stu_by_name(const void *e1, const void *e2) //按照姓名排序
{
assert(e1 && e2);
int ret = 0;
ret = strcmp(((struct stu *)e1)->name,((struct stu *)e2)->name); //strcmp 函数用来比较两个字符串大小,从第一个字符开始比,第一个字符相等时才继续往后比。
// 前者大,返回值大于0;前者小,返回值小于0;一样大,返回0;
return ret;
}
int cmp_stu_by_age(const void *e1, const void *e2) //按照年龄排序
{
assert(e1 && e2);
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
上面代码是用户根据需求编写的排序函数,下面是程序员设计的,可以接收用户设计的函数地址的函数。
void Swap(char *p1, char *p2, size_t width)
{
assert(p1 && p2);
size_t i = 0;
for (i = 0; i < width; i++) // 逐个字节进行交换
{
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
void bubble_sort(void *base, size_t num, size_t width, int(*cmp)(const void *e1, const void *e2)) // cmp是 函数指针, 存放函数的地址,可以通过地址找到(调用)函数。
{
assert(base && cmp);
size_t i = 0;
size_t j = 0;
for (i = 0; i < num - 1; i++) // 冒泡排序 每趟能确定一个元素的正确位置,一共要排 元素个数-1趟
{
for (j = 0; j < num-1-i; j++) //每一趟冒泡排序中,两两比较的次数
{
if ((cmp((char*)base + j*width, (char*)base +(j+1)* width) )> 0) // base 代表元素首地址。 (char*)base + j*width:确定j*元素的宽度,表示第j个元素
// 函数指针cmp 调用 cmp_stu_by_age,将返回值和0比较
{
Swap((char*)base + j * width, (char*)base + (j+1) * width, width); // 当前面一个元素 大于后面的元素,交换位置
}
}
}
}
int main()
{
//int arr[] = { 2,8,6,7,5,0,9,7,1,3};
struct stu arr[] = { {"bang",20},{"uzi",18} ,{"faker",19} };
int sz = sizeof(arr) / sizeof(arr[0]);
//qsort(arr, sz, sizeof(arr[0]),cmp_int);
//qsort(arr, sz, sizeof(arr[0]),cmp_stu_by_name);
//qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age); //按照名字排序
for (int i = 0; i < 3; i++)
{
printf("%s %d\n", arr[i].name, arr[i].age);
}
system("pause");
return 0;
}
结果:
按照年龄排序:
按照名字排序: