冒泡排序模拟qsort函数
创始人
2024-05-07 23:31:05
0

欢迎来到 Claffic 的博客 💞💞💞

前言:

学习C语言,一般情况下都会接触到冒泡排序,你知道吗,用冒泡排序的思想可以模拟实现qsort函数(库函数的一种,可以实现快排)跟我来看看吧。

注:此博客包含进阶知识,建议学完C语言初阶知识再进行学习哦 ~  


1. qsort 函数介绍

打开你的 C/C++资源网站/软件,搜索 qsort 函数  cplusplus - qsort 

  可以解读出:

qsort 函数的功能是排序数组中的元素;

qsort 函数不返回数据;

使用 qsort 需要传递四个参数。

传递的四个参数大有讲头,这里详细解释:

先来看看前三个:

base: 直译是 “指向数组中要排序的第一个对象的指针,转换为 void* ”。

简单说就是 要排序,你得先把你要排序的数组给我 ,那为什么要转换为 void* 呢?

这里就不得不说 void* 的利弊 了:

好处:void* 可以接收任意指针类型,包容性极强;

缺陷:接收的指针不可直接使用,也就意味着使用前要进行类型转换。

原因 就是 qsort 函数的作者不知道你要传递什么类型的数组,所以干脆就用覆盖范围最广的喽 ~

num: 直译是 “ 数组中由base指向的元素个数,size_t 是无符号整型 ” 。

这个比较好理解,就是数组中元素总和,size_t 就是 unsigned int ,因为总和不可能为负数,类型是无符号整型也理所应当了。

size: 直译是 “ 数组中每个元素的字节大小 ” 。 

这个倒是好理解,但你知道它有什么用吗?嘿嘿,这里留个小悬念 ~

看最后一个:

这里就直接解释吧:

int (*compar)(const void*,const void*) 是函数指针,它叫做 compar

它指向的函数 需要两个参数(都是 void* 型,且指向不可变);

它指向的函数 返回整型数值。

那就是要给 qsort 传个函数呗,但传递的这个函数的作用是?

你想啊,假如我用冒泡排序的思想给一个整数数组排升序,是不是先要比较相邻两个元素的大小 在来决定是否进行交换?

是的,比较两个元素就是这个函数的作用,这两个元素可以是相邻两个元素(注意:qsort 函数比较的不一定是两个相邻的元素,因为我们用冒泡排序的思想,所以可以理解为两个相邻的元素),指向它们的指针类型同样是 void* ,最广泛。

返回值呢?

简单来说,可以用两个元素做差来解释:

  a - b (a , b 都是整型)

a > b ,返回大于 0 的整数;

a = b ,返回 0 ;

a < b ,返回小于 0 的整数。

2.实现过程

充分认识了 qsort ,接下来就是用冒泡排序的思想来模拟它,

我们先来复习一遍冒泡排序:

//普通的冒泡排序:
void bub_sort(int* arr, int sz)
{for (int i = 0; i < sz - 1; i++){for (int j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){int temp = 0;temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

在这个冒泡排序中,只能实现整型类型元素的排序;

我们的目标是实现多种类型元素的排序;

所以要改善的部分是判断与交换的部分

我们先来写出框架:

void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void* e2))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){if (cmp()>0){//交换Swap();}}}}

接下来就是实现 cmp 函数Swap 函数

2.1 cmp 函数部分

如果传参类型是 整型:
直接返回差值就好。

int int_cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;//强制类型转换
}

如果传参类型是包含整型和字符串类型的 结构体:

先把结构体创建:

struct Stu
{char name[20];int age;
};struct Stu s[3] = { {"zhangsan",20},{"lisi",60},{"wangwu",30} };

如果按年龄排序结构体:

int age_cmp(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;//莫忘记强制类型转换  指向具体结构体成员
}

如果按名字排序结构体:

实际上是字符串的比较,我们很容易想到 strcmp 函数,将比较的两个字符串传入函数即可。

int name_cmp(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

 2.2 Swap 函数部分

Swap 函数就是执行 交换相邻元素 任务的

 既然两个数组的元素不能直接交换,那么我们就开辟一块小空间,通过这块小空间交换一个元素后再进行下一个元素的交换。

理应,Swap 函数需要指向数组第一个元素的指针,还有数组中每个元素的字节大小(揭开悬念)

代码:

void Swap(char* buf1, char* buf2, int size)
{for (int i = 0; i < size; i++){char temp = *buf1;*buf1 = *buf2;*buf2 = temp;buf1++;buf2++;}
}

 到这里基本上就大功告成啦

2.3函数整体代码

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include//交换函数
void Swap(char* buf1, char* buf2, int size)
{for (int i = 0; i < size; i++){char temp = *buf1;*buf1 = *buf2;*buf2 = temp;buf1++;buf2++;}
}//冒泡排序思想实现指定类型数组的排序
void bubble_sort(void* base, size_t num, size_t size, int (*cmp)(const void* e1, const void* e2))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; 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 int_cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}struct Stu
{char name[20];int age;
};int age_cmp(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int name_cmp(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}//测试部分
void int_test()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), int_cmp);for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
void struct_test()
{struct Stu s[3] = { {"zhangsan",20},{"lisi",60},{"wangwu",30} };int sz = sizeof(s) / sizeof(s[0]);bubble_sort(s, sz, sizeof(s[0]), age_cmp);}int main()
{int_test();struct_test();return 0;
}

已上传至 我的gitee ,代码拿走不谢 ~


总结:

这篇博客带大家用冒泡排序的思想模拟了 qsort 函数,应用到了 函数回调 的知识点,属于指针进阶知识,你学会了吗?

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

关注我  不迷路!!! 

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...