C程序利用冒泡排序的思想模拟实现qsort排序函数

求个赞求个赞求个赞求个赞 谢谢

先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注我哦!️️️
前言:作者:Yu
常用c程序编译器:vs2019**

qsort函数的使用

在我们模拟实现它之前,我们先搞清楚它的用法。
我们先来看qsort函数的原型

void qsort (void* base, size_t num, size_t size,int (*cmp)(const void*, const void*));

/base存放的是待排序数据中第一个对象的地址, void无具体类型,所以
什么类型都可以
/
//num代表数据个数
//size指的是一个元素有几个字节,我们知道类型决定一次访问跳过多少字节
//因为此处是void,我们是不知道一个元素是多少个字节的
//cmp函数是用来排序数据中的两个元素的函数

//假设写一个冒泡排序函数,排序字符串
//我们发现,相比于整形排序
//循环语句是一样的
//只有比较部分很交换部分可能不一样
//所以我们要使用函数指针
//该函数指针指向的函数,返回int,如果大于0,就大于,如果小于0,就小于
//就是这样设计的

我们先看看整个运用代码是怎么写的

int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
void test1()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);//求出数组元素的个数
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < 10; i++)
{
printf("%d\t", arr[i]);
}
}
int main()
{
test1();//排序整型
return 0;
}

在这个代码中,我们来逐个分析qsort函数里面四个参数
1,void *base
这个指的是我们要排列元素的数组的首元素地址,所以上面我们直接把arr传过去就好了
为什么使用void *类型?
使用void *类型使得我们这个qsort函数可以排序任何的类型的数据

2,size_t num
这个指的是数组元素的个数
3,size_t size
这个指的是每个元素的大小
为什么需要这个参数?
我们知道指针解引用的时候,或者数组里面需要访问元素的时候,我们需要直到一个元素所占的字节的大小,char类型1个字节,int类型4个字节…,qsort函数的作者为了让我们可以排序任何类型数据,所以我们需要这个参数,告诉计算机,我们一个元素是几个字节的。
4,int (cmp)(const void , const void* );
此处,是qsort函数的精髓,一个函数指针,qsort函数的作者在编写qsort函数的时候,他并不知道我们将来要用这个函数来给什么类型的数据排序,因此,qsort本身并不知道怎么去比大小,他不知道比大小的规则是什么(他并不知道3,4哪个大,因为他不知道这是什么类型的数据),因此我们我们写一个cmp(compare)函数,告诉我们的计算机,怎么去比大小。
因此,作为一个使用者,我们必须给计算机写一个cmp函数,告诉计算机怎么比,并返回一个int,int (*cmp)(const void*e1 , const void* e2);,如果这个int类型的返回值大于0,则计算机认为,e1比e2大,他就可以进行后续的排序了,反之亦然。
所以我们写了一个cmp函数

int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}

注意,这里cmp函数的类型,一定要和上面qsort函数要求的类型一一对应

int (*cmp)(const void*e1 , const void* e2)

进到这个对比函数里头,我们在比较之前,我们是肯定要解引用的,但是,void类型怎么解引用呢,所以,我们要把它强制转化成int类型,这样就可以解引用并返回一个整型了。
最后我们将上面的函数整体使用的结果打印出来就可以了

以上便是我们qsort函数的使用

接下来,让我们一起来模拟它

我们使用的是冒泡排序的双循环的方法进行实现
我们先看一下普通冒泡排序的代码

void bubble_sort(int* arr, int sz)
{
int i = 0;
int j = 0;
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 main()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
for (int i = 0; i < sz; i++)
{
printf("%d\t", arr[i]);
}
return 0;
}

我们准备使用的正是这种思想。
我们先来看完整代码

void swap(char* bulf1, char* bulf2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *bulf1;
*bulf1 = *bulf2;
*bulf2 = tmp;
bulf1++;
bulf2++;
}
}
void qsort_by_bubble(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 (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
{//由于我们不知道base里面数据是什么类型的
//因此我们找arr[j]和arr[j+1]的时候就遇到了麻烦
//因此,我们要把base强制转换成char*类型的,再利用j*width和(j+1)*width来找到各个元素
swap((char*)base + j * width, (char*)base + (j + 1) * width,width); }
}
}
}

以上就是本期博客的全部内容了,谢谢各位的耐心观看,在划走之前点个赞支持下吧!!!

【算法】C程序超详细的qsort排序函数解释和模拟的更多相关文章

  1. Java web 简单的增删改查程序(超详细)

    就是简单的对数据进行增删改查.代码如下: 1.bean层:用来封装属性及其get set方法 toString方法,有参构造方法,无参构造方法等. public class Bean { privat ...

  2. 算法学习笔记(一)C++排序函数、映射技巧与字典树

    1.头文件algorithm中有函数sort()用于排序,参数为:排序起始地址,排序结束地址,排序规则(返回bool型)例如,要将array[] = {5,7,1,2,9}升序排列,则使用: bool ...

  3. 数据挖掘领域十大经典算法之—C4.5算法(超详细附代码)

    https://blog.csdn.net/fuqiuai/article/details/79456971 相关文章: 数据挖掘领域十大经典算法之—K-Means算法(超详细附代码)        ...

  4. 标准差分进化算法matlab程序实现(转载)

    标准差分进化算法matlab程序实现 自适应差分演化算法方面的Matlab和C++代码及论文 差分进化算法 DE-Differential Evolution matlab练习程序(差异演化DE) [ ...

  5. qsort中的函数指针,及函数解释

    函数指针有何用 函数指针的应用场景比较多,以库函数qsort排序函数为例,它的原型如下: void qsort(void *base,size_t nmemb,size_t size , int(*c ...

  6. 算法课上机实验(一个简单的GUI排序算法比较程序)

    (在家里的电脑上Linux Deepin截的图,屏幕大一点的话,deepin用着还挺不错的说) 这个应该是大二的算法课程上机实验时做的一个小程序,也是我的第一个GUI小程序,实现什么的都记不清了,只记 ...

  7. qsort排序算法

      七种qsort排序方法 <本文中排序都是采用的从小到大排序> 一.对int类型数组排序 int num[100]; Sample: int cmp ( const void *a ,  ...

  8. IT技术 | 让程序员抓狂的排序算法教学视频

    点击「箭头所指处」可快速关注传智特刊微信号:CZTEKAN 原文地址:http://mp.weixin.qq.com/s?__biz=MjM5OTM4NDMyMg==&mid=20056820 ...

  9. 超强、超详细Redis数据库入门教程

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...

  10. 超强、超详细Redis数据库入门教程(转载)

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下   [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...

随机推荐

  1. ZOJ - 1610 区间修改+暴力单点查询

    一.内容 题意:给定[1,8000]区间,给定n组操作,每次将一段区间修改成某种颜色(对上一次颜色进行覆盖),最后问你能看到多少种颜色,且每种颜色有多少段. 二.思路 题目给定的区间是(x, y]左开 ...

  2. Educational Codeforces Round 110 (Rated for Div. 2) (AB签到,C题双指针,D题DP好题)

    补题链接:Here 1535A. Fair Playoff 四名选手参加了季后赛.比赛按以下方案进行:第一名选手与第二名选手比赛,第三名选手与第四名选手比赛,然后两人中的获胜者进入决赛. 众所周知,在 ...

  3. Dubbo 泛化调用在vivo统一配置系统的应用

    作者:vivo 互联网服务器团队- Wang Fei.LinYupan Dubbo泛化调用特性可以在不依赖服务接口API包的场景中发起远程调用, 这种特性特别适合框架集成和网关类应用开发. 本文结合在 ...

  4. vivo 悟空活动中台 - 微组件状态管理(下)

    本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/1DzTYIExVbK0uE_Oc7IHYw作者:悟空中台研发团队 [悟空活动中台]系列往期精 ...

  5. 彻底解决 gcr、quay、DockerHub 镜像下载难题

    在使用 Docker 和 Kubernetes 时,我们经常需要访问 gcr.io 和 quay.io 镜像仓库,由于众所周知的原因,这些镜像仓库在中国都无法访问,唯一能访问的是 Docker Hub ...

  6. Scan Synthesis Practice

    不同上升沿触发器如何进行scan chain DFT实例 Synopsys 工具文档 Mentor DFT脚本 add_clocks 0 clk - 0表示上升沿 Synopsys DFT脚本 更改n ...

  7. Cortex-M3内核介绍

    目录 Cortex Vendor - ARM介绍 ARM主要提供指令集,需要授权 ARM使用的RSIC结构,功耗比较低 Cortex M3整体架构 核心是Processor Core - 包含寄存器和 ...

  8. Verdi基础-01

    Verdi使用目标 生成fsdb波形 查看fsdb波形 追踪RTL代码 目录 Verdi历史 生成fsdb波形 三个变量&&三个命令 变量PATH LD_LIBRARY_PATH so ...

  9. 【C/C++】宏参数多对一和宏部分替换

    宏参数多对一:使用分号分隔多参数 宏部分替换:替换需要转换的再与后续宏接续 #include <stdio.h> #define _MESS_FAILED() printf("% ...

  10. 有了Composition API后,有些场景或许你不需要pinia了

    前言 日常开发时有些业务场景功能很复杂,如果将所有代码都写在一个vue组件中,那个vue文件的代码量可能就几千行了,维护极其困难.这时我们就需要将其拆分为多个组件,拆完组件后就需要在不同组件间共享数据 ...