回调函数与qsort的讲解和模拟实现
前言
回调函数是一个函数,它作为参数传递给另一个函数,并且能够在该函数内部被调用。在C语言中,回调函数通常被用于实现事件处理和排序算法中。
qsort
是C标准库中的一个排序函数,它可以对任意类型的数组进行排序。qsort
需要三个参数:要排序的数组、数组元素的个数和一个指向回调函数的指针。回调函数必须满足两个条件:能够比较数组中的元素,返回一个整数表示它们之间的大小关系;并且它应该能够被qsort
函数调用。
回调函数是一种在编程中广泛使用的技术,它允许一个函数作为参数传递给另一个函数,并在需要时被调用。这种机制使得代码更加灵活和可重用。
qsort是C语言标准库中的一个函数,用于对数组进行快速排序。它使用了回调函数作为比较函数,允许用户自定义排序规则。这使得qsort可以处理各种类型的数据,并根据不同的排序需求进行调整。
模拟实现qsort可以通过创建一个简单的排序函数来完成,该函数接受一个数组、数组的大小、比较函数作为参数。在排序过程中,使用比较函数来确定元素的顺序,并根据需要交换元素的位置。通过模拟实现qsort,可以更好地理解回调函数在排序算法中的应用,以及如何使用自定义的比较函数来满足不同的排序需求。
总之,回调函数在编程中是一种强大的技术,它使得代码更加灵活和可重用。qsort是一个使用回调函数的示例,它允许用户自定义排序规则,从而适应不同的排序需求。通过模拟实现qsort,可以深入了解回调函数在排序算法中的应用。
1. 回调函数是什么?
C语言中,回调函数是指将一个函数作为参数传递给另一个函数,并在后者中被调用的函数。
一般情况下,回调函数被用来在程序中实现事件处理和消息传递等机制。例如,当一个用户在应用程序中点击一个按钮时,应用程序会调用相应的回调函数来处理该事件。
以下是一个示例代码,展示了如何在C语言中定义和使用回调函数:
#include <stdio.h> // 回调函数定义 typedef int (*callback)(int); // 回调函数实现 int callback_function(int num) { return num * 2; } // 接收回调函数参数的函数 void accept_callback(int num, callback cb) { int result = cb(num); // 调用回调函数 printf("The result is: %d\n", result); } int main() { // 调用 accept_callback 函数,并传入回调函数指针 accept_callback(5, callback_function); return 0; }
在上述示例中,我们通过定义 callback
类型为函数指针类型,从而定义了一个回调函数类型。接着,我们定义了回调函数 callback_function
,该函数接收一个整数作为参数,并返回该参数的两倍。最后,我们通过调用 accept_callback
函数,并传入一个整数以及回调函数的指针,实现了回调函数的调用和结果输出。
需要注意的是,回调函数的实现和使用需要满足一定的约定,例如回调函数的参数和返回值类型需要与被调用函数的要求一致,否则会导致程序运行错误。
回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。回调函数不是由该函数的实现直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
//使用回调函数改造前 #include <stdio.h> int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a / b; } int main() { int x, y; int input = 1; int ret = 0; do { printf("******************\n"); printf(" 1:add 2:sub \n"); printf(" 3:mul 4:div \n"); printf("******************\n"); printf("请选择:"); scanf("%d", &input); switch (input) { case 1: printf("输入操作数:"); scanf("%d %d", &x, &y) ret = add(x, y); printf("ret = %d\n", r break; case 2: printf("输入操作数:"); scanf("%d %d", &x, &y) ret = sub(x, y); printf("ret = %d\n", r break; case 3: printf("输入操作数:"); scanf("%d %d", &x, &y) ret = mul(x, y); printf("ret = %d\n", r break; case 4: printf("输入操作数:"); scanf("%d %d", &x, &y) ret = div(x, y); printf("ret = %d\n", r break; case 0: printf("退出程序\n"); break; default: printf("选择错误\n"); break; } } while (input); return 0; }
//使用回到函数改造后 #include <stdio.h> int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a / b; } void calc(int(*pf)(int, int)) { int ret = 0; int x, y; printf("输入操作数:"); scanf("%d %d", &x, &y); ret = pf(x, y); printf("ret = %d\n", ret); } int main() { int input = 1; printf("******************\n"); printf(" 1:add 2:sub \n"); printf(" 3:mul 4:div \n"); printf("******************\n"); printf("请选择:"); scanf("%d", &input); switch (input) { case 1: calc(add); break; case 2: calc(sub); break; case 3: calc(mul); break; case 4: calc(div); break; case 0:printf("退出程序\n"); break; default: printf("选择错误\n"); break; } } while (input);.return 0; }
#include <stdio.h> #include <stdlib.h> int add(int x, int y) { return x + y; } int sub(int x, int y) { return x - y; } int mul(int x, int y) { return x * y; } int dive(int x, int y) { return x / y; } int main() { int a,x,y; int (*p[4])(int x, int y) = { add,sub,mul,dive }; while (1) { printf("需要计算的数字\n"); scanf_s("%d%d", &x, &y); printf("需要进行的操作 1 . + 2 . - 3. * 4. / 0. 退出 \n"); scanf_s("%d", &a); switch (a) { case 1:printf("%d", p[0](x, y)); break; case 2:printf("%d", p[1](x, y)); break; case 3:printf("%d", p[2](x, y)); break; case 4:printf("%d", p[3](x, y)); break; case 0:exit(0); break; default:printf("error"); continue; } } system("pause"); return 0; }
2. qsort
qsort
是C语言中的一个标准库函数,用于实现快速排序算法。它可以对任意类型的数组进行排序,只需要给出相应的比较函数即可。
qsort
的函数原型如下:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
其中,base
是要排序的数组的首地址,nmemb
是数组中元素的个数,size
是每个元素的大小(以字节为单位),compar
是用来比较数组中元素大小的函数指针。
比较函数的定义如下:
int compar(const void *a, const void *b);
函数需要返回一个整型值,表示两个元素的大小关系。如果a
小于b
,返回一个负数;如果a
等于b
,返回0;如果a
大于b
,返回一个正数。
下面是一个使用qsort
进行int
类型数组排序的例子:
#include <stdio.h> #include <stdlib.h> int cmp(const void *a, const void *b) { return *(int *)a - *(int *)b; } int main() { int arr[] = {3, 1, 4, 1, 5, 9, 2, 6}; int n = sizeof(arr) / sizeof(int); qsort(arr, n, sizeof(int), cmp); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
运行结果为:1 1 2 3 4 5 6 9
上述代码中,我们定义了一个比较函数cmp
,返回a-b
的结果,然后将其传给qsort
函数进行排序。在main
函数中,我们定义了一个int
类型的数组arr
,调用qsort
进行排序后,输出结果即可。
需要注意的是,qsort
函数是一个不稳定的排序算法,即排序后可能改变数组中相同元素的原有顺序。
2.1 使用qsort函数排序整型数据
#include <stdio.h> //qosrt函数的使用者得实现一个比较函数 int int_cmp(const void * p1, const void * p2) { return (*( int *)p1 - *(int *) p2); } int main() { int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; int i = 0; qsort(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; }
2.2 使用qsort排序结构数据
#include <stdio.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; } //strcmp - 是库函数,是专门用来比较两个字符串的大小的 //假设按照名字来比较 int cmp_stu_by_name(const void* e1, const void* e2) { return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name); } //按照年龄来排序 void test2() { struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_age); } //按照名字来排序 void test3() { struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} }; int sz = sizeof(s) / sizeof(s[0]); qsort(s, sz, sizeof(s[0]), cmp_stu_by_name); } int main() { test2(); test3(); return 0; }
汇总
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> typedef struct stu { char name[10]; char num[12]; int age; }stu; int int_cmp(const void* a,const void * b) { return *(int*)a - *(int*)b; } int double_cmp(const void* a, const void* b) { return *(double*)a - *(double*)b; } int char_cmp(const void* a, const void* b) { return strcmp((char*)a, (char*)b); } int stu_name_cmp(const void* a, const void* b) { return strcmp(((stu*)a)->name, ((stu*)b)->name); } int main() { stu s1[5] = {{"zhangsan", "123156652", 12}, {"lisi","123491235652",12}, {"wangwu", "19642588652", 12}, { "jia","1321458652",12 }, { "yi","19635288652",12 }}; stu* p; int arr[] = { 3, 1, 4, 1, 5, 9, 2, 6 }; double arr1[] = { 3.5, 1.3, 4.2, 1.6, 5.5, 9.4, 2.3, 6.6 }; char arr3[] = "abzcdefgd "; int len = (int)strlen(arr3); int n = sizeof(arr) / sizeof(int); int n1 = sizeof(stu) / sizeof(s1[0]); p = s1; qsort(arr, n, sizeof(int), int_cmp); qsort(arr1, n, sizeof(double), double_cmp); qsort(arr3, len, sizeof(char), char_cmp); qsort(s1, n1, sizeof(stu), stu_name_cmp); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); for (int i = 0; i < n; i++) { printf("%lf ", arr1[i]); } printf("\n"); printf("%s", arr3); printf("\n"); for (int i = 0; i < n; i++) { printf("%s ", (s1[i]).name); } return 0; }
3. qsort函数的模拟实现
使用回调函数,模拟实现qsort
(采用冒泡的方式)。
#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 }; 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; }
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> typedef struct stu { char name[10]; char num[12]; int age; }stu; int int_cmp(const void* a,const void * b) { return *(int*)a - *(int*)b; } int double_cmp(const void* a, const void* b) { return *(double*)a - *(double*)b; } int char_cmp(const void* a, const void* b) { return strcmp((char*)a, (char*)b); } int stu_name_cmp(const void* a, const void* b) { return strcmp(((stu*)a)->name, ((stu*)b)->name); } void _swap(void* p1, void* p2, int size) { int i = 0; char temp; for (i = 0; i < size; i++) { temp = *((char*)p1 + i); *((char*)p1 + i) = *((char*)p2 + i); *((char*)p2 + i) = temp; } } void my_qsort(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() { stu s1[5] = {{"zhangsan", "123156652", 12}, {"lisi","123491235652",12}, {"wangwu", "19642588652", 12}, { "jia","1321458652",12 }, { "yi","19635288652",12 }}; stu* p; int arr[] = { 3, 1, 4, 1, 5, 9, 2, 6 }; double arr1[] = { 3.5, 1.3, 4.2, 1.6, 5.5, 9.4, 2.3, 6.6 }; char arr3[] = "abzcdefgd "; int len = (int)strlen(arr3); int n = sizeof(arr) / sizeof(int); int n1 = sizeof(stu) / sizeof(s1[0]); p = s1; my_qsort(arr, n, sizeof(int), int_cmp); qsort(arr1, n, sizeof(double), double_cmp); qsort(arr3, len, sizeof(char), char_cmp); qsort(s1, n1, sizeof(stu), stu_name_cmp); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); for (int i = 0; i < n; i++) { printf("%lf ", arr1[i]); } printf("\n"); printf("%s", arr3); printf("\n"); for (int i = 0; i < n; i++) { printf("%s ", (s1[i]).name); } return 0; }