目录

一、什么是函数回调

二、qsort()快速排序

1. 库函数qsort()的声明

2. qsort()对不同类型数据进行排序示例

2-1先输入需要排序的不同类型数据:

2-2对qsort()需要的实参,即首元素地址,元素个数,元素大小,比较函数进行计算和输入。

2-3排序方法函数的建立

2-4打印各类数据的函数

2-5完整代码

三、冒泡排序实现不同类型数据的排序

3-1建立交换前后参数

3-3全部代码


一、什么是函数回调

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

二、qsort()快速排序

1. 库函数qsort()的声明

void qsort(void *base,//指向要排序的数组的第一个元素的指针。size_t nitems,//指向要排序的数组的第一个元素的指针。size_t size,//数组中每个元素的大小,以字节为单位。int (*compar)(const void *, const void*)//用来比较两个元素的函数。) 
  1. base -- 指向要排序的数组的第一个元素的指针,因为不知传入的实参是什么类型,所以形参是无参数类型void。
  2. nitems -- 由 base 指向的数组中元素的个数。
  3. size -- 数组中每个元素的大小,以字节为单位,由此可知传入参数的类型,如int为四个字节,char为一个字节。
  4. compar -- 用来比较两个元素的函数,这个函数需要自己创建一个函数,确定比较方法。

2. qsort()对不同类型数据进行排序示例

2-1先输入需要排序的不同类型数据:

#include<stdio.h>struct St
{    char name[40];int age;float score;
} St;
int main()
{int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型数据示例char arr2[] = "hello";//字符型数据示例struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体数据示例return 0;
}

2-2对qsort()需要的实参,即首元素地址,元素个数,元素大小,比较函数进行计算和输入。

因结构体内部成员不同,因此按照每个成员的排序顺序也不同,以本文为例,分为以姓名排序(以首元素的ascii码值的大小进行排序)、以年龄排序、以成绩排序三种,因此要写不同的排序函数。

int main()
{int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型示例char arr2[] = "hello";//字符示例struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体示例int szarr1 = sizeof(arr1) / sizeof(arr1[0]);//整型元素个数int szarr2 = sizeof(arr2) / sizeof(arr2[0]);//字符元素个数int szs= sizeof(s) / sizeof(s[0]);//结构体元素个数qsort(arr1, szarr1, sizeof(arr1[0]), cmp_int);//整型排序qsort(arr2, szarr2, sizeof(arr2[0]), cmp_char);//字符排序qsort(s, szs, sizeof(s[0]), cmp_st_by_name);//结构体按姓名排序qsort(s, szs, sizeof(s[0]), cmp_st_by_age);//结构体按年龄排序qsort(s, szs, sizeof(s[0]), cmp_st_by_score);//结构体按成绩排序return 0;
}

2-3排序方法函数的建立

计算前面的数e1与后面的数e2的差,大于0则返回正数,则交换,小于0则返回复数,不交换,打印出来为正序,若要求逆序,则改成e2-e1

int cmp_int(const void *e1, const void *e2)//比较整型方法
{return *((int*)e1)-*((int*)e2);
}
int cmp_char(const void* e1, const void* e2)//比较字符型方法
{return strcmp(e1, e2);//strcmp()比较字符串大小,用ascii码值比较
}
int cmp_st_by_name(const void* e1, const void* e2)//以姓名排序比较结构体方法
{return strcmp(((struct St*)e1)->name, ((struct St*)e1)->name);
}
int cmp_st_by_age(const void* e1, const void* e2)//以年龄排序比较结构体方法
{return ((struct St*)e1)->age-((struct St*)e2)->age;
}
float cmp_st_by_score(const void* e1, const void* e2)//以分数排序比较结构体方法
{if (((struct St*)e1)->age > ((struct St*)e2)->age)return 1;else if (((struct St*)e1)->age < ((struct St*)e2)->age)return -1;else return 0;}

2-4打印各类数据的函数

void print_int(const int *arr, const int sz)//打印整型
{int i;for (i = 0; i < sz; i++){printf("%d", arr[i]);}printf("\n");}
void print_char(const char* arr, const int sz)//打印字符串
{int i=0;for (i = 0; i < sz; i++){printf("%c", arr[i]);}printf("\n");}
void print_st(const struct St* arr, int sz)//打印结构体类型数据
{int i;for (i = 0; i < sz; i++){printf("%s %d %.1f, ",arr[i].name,arr[i].age,arr[i].score);}printf("\n");}

2-5完整代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct St
{   char name[40];int age;float score;
} St;
void print_int(const int *arr, const int sz)//打印整型
{int i;for (i = 0; i < sz; i++){printf("%d", arr[i]);}printf("\n");}
void print_char(const char* arr, const int sz)//打印字符串
{int i=0;for (i = 0; i < sz; i++){printf("%c", arr[i]);}printf("\n");}
void print_st(const struct St* arr, int sz)//打印结构体类型数据
{int i;for (i = 0; i < sz; i++){printf("%s %d %.1f, ",arr[i].name,arr[i].age,arr[i].score);}printf("\n");}
int cmp_int(const void *e1, const void *e2)//比较整型方法
{return *((int*)e1)-*((int*)e2);
}
int cmp_char(const void* e1, const void* e2)//比较字符型方法
{return strcmp(e1, e2);//strcmp()比较字符串大小,用ascii码值比较
}
int cmp_st_by_name(const void* e1, const void* e2)//以姓名排序比较结构体方法
{return strcmp(((struct St*)e1)->name, ((struct St*)e1)->name);
}
int cmp_st_by_age(const void* e1, const void* e2)//以年龄排序比较结构体方法
{return ((struct St*)e1)->age-((struct St*)e2)->age;
}
float cmp_st_by_score(const void* e1, const void* e2)//以分数排序比较结构体方法
{if (((struct St*)e1)->age > ((struct St*)e2)->age)return 1;else if (((struct St*)e1)->age < ((struct St*)e2)->age)return -1;else return 0;}int main()
{int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型示例char arr2[] = "hello";//字符示例struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体示例int szarr1 = sizeof(arr1) / sizeof(arr1[0]);//整型元素个数int szarr2 = sizeof(arr2) / sizeof(arr2[0]);//字符元素个数int szs= sizeof(s) / sizeof(s[0]);//结构体元素个数qsort(arr1, szarr1, sizeof(arr1[0]), cmp_int);//整型排序qsort(arr2, szarr2, sizeof(arr2[0]), cmp_char);//字符排序qsort(s, szs, sizeof(s[0]), cmp_st_by_name);//结构体按姓名排序print_st(s, szs);qsort(s, szs, sizeof(s[0]), cmp_st_by_age);//结构体按年龄排序print_st(s, szs);qsort(s, szs, sizeof(s[0]), cmp_st_by_score);//结构体按成绩排序print_st(s,szs);print_int(arr1, szarr1);print_char(arr2, szarr2);return 0;
}

输出结果:

lisi 21 80.0, wangwu 22 56.5, zhangsan 20 90.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
022345679
ehllo

三、冒泡排序实现不同类型数据的排序

使用冒泡排序方法进行排序和qsort()需要的参数类似,利用的比较函数是相同的,只是排序的方法有差异,只需自行建立冒泡排序的函数代替qsort()即可。

3-1建立交换前后参数

void Swap(char* buf1, char* buf2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;//一对字节一对字节交换}
}

因为Swap的形参是char*类型,一次只能访问一个字节,因此对调时是一个字节一个字节对调,加入字节长度可知有几个字节要对掉,也就是要对调的次数,创建一个循环实现。

反观以下普通冒泡排序实现数字交换功能时,因传入的形参是int*,一次就能访问四个字节,只要交换一次,解引用后就可以访问到形参接收到的指针指向的参数的值,不用再设置循环。

void exchange(int* a, int* b)
{int tmp = 0;tmp = *a;*a = *b;*b = tmp;
}

3-2冒泡函数主体


void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{int i = 0;for (i = 0; i < sz - 1; i++)//进行冒泡排序的趟数{int j = 0;for (j = 0; j < sz - 1 - i; j++)//一趟中两个交换{//if (arr[j] > arr[j + 1])if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
//base的类型是void,不能直接加j,而不知传入的实参是什么类型,所以转换成占一个字节的char类型,
//加j*wide能跳过j个宽度的字节,宽度就是传入实参的字节长度{//两个元素的交换Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}

3-3全部代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct St
{   char name[40];int age;float score;
} St;
void print_int(const int *arr, const int sz)//打印整型
{int i;for (i = 0; i < sz; i++){printf("%d", arr[i]);}printf("\n");}
void print_char(const char* arr, const int sz)//打印字符串
{int i=0;for (i = 0; i < sz; i++){printf("%c", arr[i]);}printf("\n");}
void print_st(const struct St* arr, int sz)//打印结构体类型数据
{int i;for (i = 0; i < sz; i++){printf("%s %d %.1f, ",arr[i].name,arr[i].age,arr[i].score);}printf("\n");
}int cmp_int(const void *e1, const void *e2)//比较整型方法
{return *((int*)e1)-*((int*)e2);
}
int cmp_char(const void* e1, const void* e2)//比较字符型方法
{return strcmp(e1, e2);//strcmp()比较字符串大小,用ascii码值比较
}
int cmp_st_by_name(const void* e1, const void* e2)//以姓名排序比较结构体方法
{return strcmp(((struct St*)e1)->name, ((struct St*)e1)->name);
}
int cmp_st_by_age(const void* e1, const void* e2)//以年龄排序比较结构体方法
{return ((struct St*)e1)->age-((struct St*)e2)->age;
}
float cmp_st_by_score(const void* e1, const void* e2)//以分数排序比较结构体方法
{if (((struct St*)e1)->age > ((struct St*)e2)->age)return 1;else if (((struct St*)e1)->age < ((struct St*)e2)->age)return -1;else return 0;}
void Swap(char* buf1, char* buf2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;//一对字节一对字节交换}
}void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{int i = 0;for (i = 0; i < sz - 1; i++)//进行冒泡排序的趟数{int j = 0;for (j = 0; j < sz - 1 - i; j++)//一趟中两个交换{//if (arr[j] > arr[j + 1])if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)//base的类型是void,不能直接加j,而不知传入的实参是什么类型,所以转换成占一个字节的char类型,加j*wide能跳过j个宽度的字节,宽度就是传入实参的字节长度{//两个元素的交换Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}
int main()
{int arr1[] = { 2,3,5,6,7,4,2,9,0 };//整型示例char arr2[] = "hello";//字符示例struct St s[] = { {"zhangsan",20,90.5},{"lisi",21,80} ,{"wangwu",22,56.5}};//结构体示例int szarr1 = sizeof(arr1) / sizeof(arr1[0]);//整型元素个数int szarr2 = sizeof(arr2) / sizeof(arr2[0]);//字符元素个数int szs= sizeof(s) / sizeof(s[0]);//结构体元素个数bubble_sort(arr1, szarr1, sizeof(arr1[0]), cmp_int);bubble_sort(arr2, szarr2, sizeof(arr2[0]), cmp_char);bubble_sort(s, szs, sizeof(s[0]), cmp_st_by_name);print_st(s, szs);bubble_sort(s, szs, sizeof(s[0]), cmp_st_by_age);print_st(s,szs);  bubble_sort(s, szs, sizeof(s[0]), cmp_st_by_score);print_st(s, szs);print_int(arr1, szarr1);print_char(arr2, szarr2);return 0;
}

输出结果:

zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
zhangsan 20 90.5, lisi 21 80.0, wangwu 22 56.5,
022345679
ehllo
-

基于函数回调方法对qsort()进行修改,使用冒泡排序实现对不同类型数据的排序相关推荐

  1. c语言函数指针,基于函数回调模拟实现qsort函数,实测案例

    前言 qsort函数C语言编译器函数库自带的排序函数. qsort 的函数原型是void qsort (void*base,size_t num,size_t width,int (__cdecl*c ...

  2. R语言基于多字段(多数据列、multiple columns)对dataframe的行数据进行排序(Ordering rows)实战:使用R原生方法、data.table、dplyr等方案

    R语言基于多字段(多数据列.multiple columns)对dataframe的行数据进行排序(Ordering rows)实战:使用R原生方法.data.table.dplyr等方案 目录

  3. 练习-编写函数对结构体类型数据进行排序

    第1关:编写函数对结构体类型数据进行排序 任务描述 本关任务:定义学生结构体数据类型,从键盘输入一批学生的信息,编写函数将这批学生按姓名排序. 相关知识 结构体变量之间整体是不可以比较大小的,结构体变 ...

  4. c++引用另一个类的方法_VlookUp函数使用方法,一张表引用另一张表的数据。

    Excel里面的Vlookup函数是很常用的函数,也是非常实用的函数.这里大致讲一下这个函数所能实现的功能,我们讲的通俗一点,比如有两张表,第一张表有学号.姓名信息,另一张表中有学号.成绩信息,当第一 ...

  5. mysql错误修改数据_使用正则表达式快速修改mysql中错误的varchar类型数据

    昨天早上发现日志中有错误信息:Integer到String类型转换异常. 由于程序问题,导致数据库中的varchar列存入的json字符串不符合要求,这些json字符串在反序列化成Map之后就会报错. ...

  6. 12.从入门到精通:Python字典,创建字典,访问字典的值,修改字典,删除字典,字典键的特性,字典内置函数和方法

    12.从入门到精通:Python字典,创建字典,访问字典的值,修改字典,删除字典,字典键的特性,字典内置函数和方法 Python字典 创建空字典 访问字典里的值 修改字典 删除字典元素 字典键的特性 ...

  7. C语言中的函数指针、函数的直接/间接调用、C# 委托(自定义委托、内置泛型委托、委托的实例化、委托的一般使用(模板方法、回调方法)、泛型委托、多播委托、同步/异步使用委托)

    文章目录 C语言中的函数指针 函数的直接调用与间接调用 Java中没有与委托对应的功能实体 C# 委托 C# 自定义委托类型 C# 内置泛型委托类型 委托的实例化 委托也支持泛型的使用 委托的一般使用 ...

  8. Java回调方法详解

    回调在维基百科中定义为: 在计算机程序设计中,回调函数,是指通过函数参数传递到其他代码的,某一块可执行代码的引用. 其目的是允许底层代码调用在高层定义的子程序. 举个例子可能更明白一些:以Androi ...

  9. php 匿名方法,PHP基于Closure类创建匿名函数的方法详解

    本文实例讲述了PHP基于Closure类创建匿名函数的方法.分享给大家供大家参考,具体如下: Closure 类 用于代表匿名函数的类. 匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象. ...

最新文章

  1. pytorch垃圾分类
  2. linux 安装 celluloid 视频播放器
  3. datagrid表头与数据列宽度不对齐_easyui datagrid标题列宽度自适应
  4. 10.30T2 二分+前缀和(后缀和)
  5. jQuery图片提示和文字提示
  6. 函数递归方法反转字符串
  7. 总结一年来的前端学习心得
  8. I/O多路复用技术是什么?
  9. 自动驾驶_感知_目标检测(基于图像)
  10. 事件委托(代理)的理解
  11. 判断是不是数字 Java_java如何判断是不是数字
  12. 三分钟了解区块链AR游戏Triffic2.0版本
  13. 开源网安实现高效、高精度的静态应用安全检测 -CodeSec
  14. 文件不见还占用空间咋修复
  15. GScan:Linux Checklist自动化检测
  16. ORB-SLAM2原理分析
  17. 老牛知点所以然-Deepin Linux搭建Swift开发环境
  18. 奇偶校验,异或校验,和校验,nios串口校验
  19. 关于在xp(sp3 专业版)下安装sql2005开发版图解
  20. Spring boot 配置文件yml的用法

热门文章

  1. html输入框自动对齐,html如何设置文本框对齐
  2. c语言牛逼,C语言牛逼代码
  3. VUE弹窗加载另一个VUE页面
  4. 计算机网络——传输层の选择题整理
  5. Scrapy爬取新浪微博用户信息、用户微博及其微博评论转发
  6. 市场分析-全球与中国纳米复合太阳能电池市场现状及未来发展趋势
  7. SQLServer Stuff函数的用法
  8. viper4android md,【超级街霸4安卓版】超级街霸4安卓完整移植版游戏下载-街机中国...
  9. 大学python笔记整理_python学习笔记整理(一)
  10. FAIR开源Detectron