1.从qsort函数中得到启示
C语言中有一个库函数qsort,可以实现对任意类型数组进行排序,其函数声明如下
其中base是数组首元素地址,num是无符号整型,意为数组元素个数,size是数组元素中每个元素的大小,单位为字节,而最后一个是一个函数指针,指向的函数会告诉计算机比较两元素的方法,比如比较两个结构体的大小,不能直接想1<2那样简单的直接比较,可以根据结构体中的元素进行比较,比如
typedef struct stu
{
int age;
char name[20];
}stu;
这个结构体,可以比较age得出两个结构体之间的大小关系,也可以比较name字符串得出二者大小关系。qsort中的函数指针就是指向这样的一个函数,这个函数返回值为int,若返回值大于0,则前大于后。
2.改造冒泡排序
void bubble(int arr[], int sz)
{
int i, j;
for (i = 0; i < sz - 1; i++)
{
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
这个冒泡排序中int arr[]是需要改变的,同时if语句中的两元素比较也需要改变,还有两元素的交换也需要改变,因为不清楚是什么类型的数据,就不能确定临时变量tmp的类型。同时该函数参数也与qsort一致。
3.代码实现
函数参数与qsort一致,这里以比较上面stu结构体的name为例。
void bubble_sort(void* base, size_t num, size_t len, int(*pf)(const void* p1, const void* p2))
base是首元素地址,num是数组元素个数,len是单元素大小,pf是函数指针。
同时实现比较函数。将两个元素的地址传过去。
int name_cmp(const void* p1, const void* p2)
{
return strcmp(((stu*)p1)->name, ((stu*)p2)->name);
}
之后是交换函数,还是传两个元素的地址。
void swap(void* p1, void* p2, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
要交换两个元素,只需要将每个元素单个字节的元素交换就行了,例如某元素四个字节
只要像这样交换每个字节的数字就可以了,为此需要将p1,p2类型强制转化为char*类型,因为char* 指针可访问的大小为一个字节。
void swap(void* p1, void* p2, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
最后是bubble_sort实现
void bubble_sort(void* base, size_t num, size_t len, int(*pf)(const void* p1, const void* p2))
{
int i, j;
for (i = 0; i < num - 1; i++)
{
for (j = 0; j < num - 1 - i; j++)
{
if (pf((char*)base+j*len,(char*)base+(j+1)*len) > 0)
{
swap((char*)base + j * len, (char*)base + (j + 1) * len,len);
}
}
}
}//num是需要排序的元素个数,len是一个元素的字节长度,base是首元素的地址,pf是一个函数指针,指向一个声明元素比较方法的函数
测试一下
int main()
{
stu s[4] = { {13,"roboko"},{11,"naruto"},{15,"sasuke"},{18,"sakura"} };
bubble_sort(s, 4, sizeof(stu), name_cmp);
for (int i = 0; i < 4; i++)
{
printf("%s\n", s[i].name);
}
return 0;
}
打印结果确实是从小到大排序的。