上一篇博客我们说过会把回调函数的一些知识再给大家讲一遍
这里把void*强制类型转化为struct Stu*,用->操作符找到age这个元素,然后对年龄进行快速排序
//void qsort(void* base, size_t num, size_t size,int (*compar)(const void*e1, const void*e2)); #include<stdio.h> #include<stdlib.h> 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; } void test() { struct Stu s[3] = { { "zhangsan", 20 }, { "lisi", 30 }, { "wangwu", 10 } }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_age); } int main() { test(); return 0; }
那我们如果要将字符串进行快速排序,我们还是按照age的排序方式来排序嘛?答案是不是,这里我们要用到字符串比较函数strcmp,现在我们来看下列代码,F11走到函数内部进行排序,我们看到的结果就是lisi wangwu zhangsan
//void qsort(void* base, size_t num, size_t size,int (*compar)(const void*e1, const void*e2)); #include<stdio.h> #include<stdlib.h> #include<string.h> struct Stu { char name[20]; int age; }; int cmp_stu_by_name(const void* e1, const void* e2) { //比较名字就是比较字符串 //字符串比较不能直接<>=来比较,需要用到strcmp函数 return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name); //return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age; } void test() { struct Stu s[3] = { { "zhangsan", 20 }, { "lisi", 30 }, { "wangwu", 10 } }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_name); } int main() { test(); return 0; }
这里再次给大家把qsort函数强调一下
void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*));
第一个参数:待排序数组的首元素的地址
第二个参数:待排序数组的元素个数
第三个参数:待排序数组的每个元素的大小,单位为字节
第四个参数:是函数指针,比较两个元素的所用函数的地址,这个函数使用者自己实现,函数指针的两个参数是待比较的两个元素的地址
#include <stdio.h> int int_cmp(const void* p1, const void* p2) { return (*(int*)p1 - *(int*)p2); } void _swap(void* p1, void* p2, int size) { int i = 0; for (i = 0; i < size; i++) { char tmp = *((char*)p1 + i); *((char*)p1 + i) = *((char*)p2 + i); *((char*)p2 + i) = tmp; } } void bubble(void* base, int count, int size, int(*cmp)(void*, void*)) { int i = 0; int j = 0; for (i = 0; i < count - 1; i++) { for (j = 0; j < count - i - 1; j++) { if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0) { _swap((char*)base + j * size, (char*)base + (j + 1) * size, size); } } } } int main() { int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; //char *arr[] = {"aaaa","dddd","cccc","bbbb"}; int i = 0; bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp); for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
这里给大家详细解释一下这个代码
为什么我们要写cmp((char*)base + j * size, (char*)base + (j + 1) * size)呢???
因为当j=0的时候,这个函数的参数就代表第一个元素和第二个元素的地址,强制类型转化为char*而不是Int*的原因是强制类型转化为Int*然后+1会让地址向后移动四个字节,对于如果我们给你传过来的是一个结构体类型,double型,float型就不合适,所以Int*不考虑,对于为什么要强制类型转换为char*指针,char*指针加1跳过一个字节,当我+size的时候就跳过size个字节,这是我们就把我们相邻两个元素的地址求出来了,然后把地址带到cmp这个函数中去了,但他返回cmp函数的值大于0,我们就进行交换,那我们应该怎么交换呢???这里我们就设计一个_swap函数,传的参数是(char*)base + j * size, (char*)base + (j + 1) * size, size,我们为什么还要传一个size呢?因为你应该告诉我你这个两个字符各是几个字节,让我交换相应的对数,所以我们应该把这个元素的大小传过去,我们进到_swap函数进行交换,交换完了过后再*p1++,*p2++指向下一个值 ,再进行下一组交换,接着我们再写出这行代码,看下面代码,进行正负数的返回,返回给cmp函数判断正负数,是整数就进行交换,希望大家能够理解
#include <stdio.h> int int_cmp(const void* p1, const void* p2) { return (*(int*)p1 - *(int*)p2); }
这是一个一般的冒泡排序的模型,上面的代码就只是这个一般的冒泡排序的一个升华,本质是没变的,里面的排序还是正常的将两个元素进行交换,直到交换成升序为止
这里再给大家做一下说明
使用bubble_sort的程序员一定要知道自己排序的是什么数据,他就应该知道如何比较待排序数组中的元素,实现bubble_sort函数的程序员,他不知道未来排序的数据类型,那程序员也不知道待比较的两个元素的类型
本章终!