C语言----冒泡排序进阶

      冒泡排序大家应该到写过吧。但大家可能知道到的冒泡排序有两种方法。而我呢,最近学习到了另外一种方法,现在知道三种方法了。所以想与大家分享一下。但是缺点是第三种是第二种的自实现版。第一种就是我们平常写的普通冒泡排序。第二种就是qsort。第三种就是my_qsort。好那么我们就这三种冒泡排序来讲述。

普通冒泡

       大家学习肯定都是先易后难。我们也就先从大家最先学习的冒泡排序开始。当然我不知道,大家对于最常见的冒泡排序是如何理解的,我就先讲解我自己对于冒泡排序的见解。我是这样认为的。因为需要冒泡排序的话,那么就是需要排序后的数组依照升序或者降序来排序,那么我就有双循环语句来写。例如一个数组有10个元素,且下标为0的元素是最大的元素的话。那么我用下标0的元素依次与下一个元素比较,大于的话,用一个零时变量来使这两个值交换。一直到下标为9的时候停止。然后进行下一个循环。当然,因为我已经遍历了一遍确定现在的下标为9的元素是数组中最大的元素所以我们在下一次遍历的时候就可以减少对最后的元素比较。好,那么接下来我们就用代码来更加详细的讲解。

       不知道我的代码与大家想的是否有太多的不同之处。或者大家认为这样的代码还有地方可以简洁,大家可以在下方评论区不腻赐教。但其实大家看了上面的代码是否觉得有点啰嗦且繁琐啊。如果我们运气不好的话。这个代码我们要遍历36遍。空间复杂度是否有时候不好满足呀。并且我们如果后面改了,不用整型数组,我们有char类型数组的话。这个代码是不是就不能直接使用了。当然我们可以依照这个模板写一个char类型的冒牌排序,但是大家是否觉得再写一个的话,是否就有点太麻烦了。那是否有这个简单且适应其他类型排序的排序方法嘞。嘿,还真有。在c语言编辑的时候,编辑者就想到了,后面的使用可能会需要对数组进行排序,那么我就写一个库函数吧,后面额人直接使用库函数再添加一些关键数据就可以排序了。这就是我接下里想与大家分享的知识。库函数qsort。

库函数qsort

       大家也知道了我们接下来要讲的是库函数qsort。那我们先来了解qsort是什么,由什么构成的

void qsort(void *base,size_t nmemb,size_t size,int (*compar)(const void *, const void *));

       头文件:<stdlib.h> qsort()函数的功能是对数组进行排序,数组有nmemb个元素,每个元素大小为size。打大家看上面这个肯定对qsort还是不了解。那么我们直接用代码来实践解决。

      当然因为是库函数所以头文件肯定是不能少的,我只是在前面的时候写过了没有照下来,大家在使用的时候记得写出来就可以了。大家看了后,可能会想,不是说可以适用于所有类型吗。你这不是char类型吗?但是大家可以看一下,我在判断大小的时候用的是void*来接收的。为什么用void*来接收嘞。这就不得不说void*的作用了。void大家都知道,无类型,那么无类型的话是不是所有类型的可以接收,相当于一个五边形战士,你来什么对手我都可以打败。但是大家需要注意到,最大的对手自己,所有void*不可以进行就算改变。它只能接收,不能进行改变。这样大家知道我们我在判断大小的时候,返回值的时候要将p1和p2强转为char类型了吧。所有qsort可以排序任意类性数组真相大白了。我们需要在给qsort传递判断大小的时候需要用void*来接收(因为void*可以接收任意类型)。然后返回的时候再强转为数组的类型(使用者肯定知道自己需要排序的数组是什么类型),这样qsort就完美的写出了。当然我可以在写一个int类型的排序,只需要在这个代码上面修改一些部分。

       大家可以对照上面的图片,我们写另外一个类型的排序数组,不需要完全重写一个代码,我们只需要将一些关键的类型改变就可以了 。

注:qsort比较大小是使用的ascll码来比较的!!!

自实现qsort

    当我们知道qsort如何使用了后,肯定不能止步于此呀,我们要完全将这个函数吃透的话,最好直接写一个代码来实现这个功能。那么接下来我们写的就是my_qsort。大家学习了上面的代码后,就是如果自己写一个的话,需要干什么。我们就以上面的代码来。我们先写,然后总结:

int daxiao(const void *p1,const void *p2)//判断大小
{return *(int*)p1 - *(int*)p2;
}
void jiaohuan(char*p1, char*p2, size_t haa)//交换值,char类型是为了方便交换,多循环几次就交换全部了
{for (int a = 0; a < haa; a++){char count = *p1;*p1 = *p2;*p2 = count;p1++;p2++;}
}
void my_qsort(void*arr,size_t sz,size_t ha,int (*pf)( void *p1,void *p2))
{for (int a = 0; a < sz - 1; a++){for (int y = 0; y < sz - 1 - a; y++){if (pf((char*)arr + y *ha, (char*)arr + (y + 1)*ha)>0)//判断,如果大于就交换小于不管jiaohuan((char*)arr + y*ha, (char*)arr + (y + 1)*ha,ha);}}
}
void dayin(int *arr, int sz)//打印结果
{for (int yy = 0; yy < sz; yy++){printf("%d ", arr[yy]);}
}
void xixi()
{int arr[] = { 9, 8, 6, 7, 2, 3, 6, 1, 0, 12 };int sz = sizeof(arr) / sizeof(arr[0]);my_qsort(arr, sz, sizeof(arr[0]), daxiao);dayin(arr, sz);
}
int main()
{xixi();return 0;
}

        上面是my_qsort的全部代码,那么我们接下来分段来解释每段代码的作用。首先主函数和创建数组传递参数这个大家知道吧。我们先解读一下my_qsort中的数据含义。arr肯定是数组名,sz是数组元素个数,sizeof(arr[0])是数组元素大小,daxiao判断升降序。

        我们也都知道qsort一些关键数据需要用void*来接收(因为void*的特性)。但大家应该也注意到了在my_qsort最后接收数据的时候,我们使用的是int (*pf)( void *p1,void *p2)。那这个是什么嘞。首先大家要知道这个叫函数指针,因为我们在这个代码中包含了另外一个需要使用的代码,使用需要将确定其使用的指针名,数据,返回值(当然我们后面会详细的讲解一下这个是什么东西,大家现在可以先记住这个是什么东西,长什么样子)。然后进入代码里面还是经典的双循环。然后判断,那么就是我刚刚说的函数指针判断大小了

        那么我们也只是说了,这个代码只是包含的另外一个,那么这个代码是不完全的,所以我们接着就要去晚上这个判断大小的代码。因为函数指针int (*pf)( void *p1,void *p2)中*pf就是这个指针的名字。那么我们接下来( void *p1,void *p2)就是传递的参数,所以大家可以将pf((char*)arr + y *ha, (char*)arr + (y + 1)*ha)理解为子程序名(参数,参数)。那么这里了解了,我们就来完整这个代码:

      首先为什么是daxiao这个数组名,是因为在创建数组my_qsort中我们就将判断大小的囊位置确定了名字就叫daxiao所以以防程序错误,我们名字需要一样。然后也是老样子,相减返回,来确定大小。然后回到my_qsort中判断是想要升序还是降序所以交换。

     这里大家需要注意的是,为什么我们在接收数据的时候强转char类型。因为char类型只有1个字节。大家应该注意到了吧,我们传递过来的数据中除了交换的两个元素外还有一个字节大小。我们把这两个结合,大家是否想到了。1个字节在c语言数据类型中是最小的,并且使用的类型大小都是2的倍数,那么我们只需要多循环几次,岂不是就可以用1个字节依次交换就交换结束了。然后就是最后的步骤打印了。当然我们在开头就写了打印的代码了。这里就不多赘述了,我们直接看结果。

        所以自实现my_qsort只需要以下加点:

1:主函数,创建数组

2:my_qsort接收数据,双循环,判断大小(是否升降序)

3:函数指针实现判断大小

4:交换数据

5:写交换结果

         这些就是my_qsort的大概步骤了。当然还有步骤需要大家了解,大家可以多看一下来增加对这个代码的熟悉度。好了如果还有很多不对的地方,希望大家可以在下方评论区写出来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/725277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab梁单元有限元编程 | 铁木辛柯梁 | 欧拉梁 | Matlab源码 | 理论文本

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

如何恢复edge的自动翻译功能

介绍&#xff1a;对于英文不好的小伙伴&#xff0c;把英语翻译成中文是有帮助的&#xff0c;而edge可以直接对英文页面翻译这一功能更是受人喜爱&#xff0c;但是&#xff0c;最近发现这一项功能消失了。 原始界面&#xff1a; 下面展示如何恢复该功能。 1.打开edge&#xff…

day06-网路编程

#include <myhead.h>int do_add(sqlite3 *ppDb) {int numb;char name[20];int age;int salary;printf("请输入要插入的信息:");scanf("%d %s %d %d", &numb, name, &age, &salary);char sql[128] "";sprintf(sql, "INSE…

Flutter(四):SingleChildScrollView、GridView

SingleChildScrollView、GridView 遇到的问题 以下代码会报错: class GridViewPage extends StatefulWidget {const GridViewPage({super.key});overrideState<GridViewPage> createState() > _GridViewPage(); }class _GridViewPage extends State<GridViewPage&g…

vscode 通义灵码 插件自动写代码

安装插件 通义灵码安装教程-阿里云 点击立即安装 我是已经安装成功了&#xff0c;所以如下图&#xff0c;没安装的会显示安装&#xff0c;点击安装即可 安装成功之后 侧边栏会出现图标 登录 使用 在编辑框中输入 问题 &#xff0c;会自动生成代码和对应的说明

Cloud+Consul

Cloud整合Zookeeper代替Eureka-CSDN博客 Consul简介 Consul是一套开源的分布式服务发现和配置管理系统 What is Consul? | Consul | HashiCorp DeveloperConsul is a service networking solution that delivers service discovery, service mesh, and network security ca…

Redis中的RDB和AOF持久化机制(一)

Redis持久化 RDB快照(snapshot). 在默认情况下&#xff0c;Redis将内存数据库快照保存在名字为dump.rdb的二进制文件中.Redis可以进行设置,让它在"N秒内数据集至少有M个改动"这一条件被满足时&#xff0c;自动保存一次数据集。比如说&#xff0c;以下设置会让Redis…

机器视觉 /从bottle.hdev示例程序开启HalconHDevelop征程

文章目录 概述示例程序bottle.hdev源码Step 0: PreparationsStep 1: Segmentation - 读取并显示图片Step 1: Segmentation - 创建并设置OCR模型Step 1: Segmentation - 文本分割与识别计算结果显示内存释放 导出为C代码导出为C代码配置 VS Halcon 环境VS程序执行结果HTuple hv…

LeetCode刷题---填充每个节点的下一个右侧节点指针

官方题解:LeetCode官方题解 解题思想: 因为是一棵满二叉树&#xff0c;所以除了叶子节点外的其他节点都有两个子节点。 可以根据每一层来依次遍历 从根节点开始&#xff0c;根节点的左子节点的next节点就指向根节点的右子节点 因为根节点的next节点为NULL&#xff0c;开始从根…

DR模式下LVS负载均衡聚集部署实验

目录 1、实验准备 2、配置负载调度器&#xff08;ens33&#xff1a;192.168.80.9 VIP:192.168.80.188&#xff09; 2.1 配置虚拟ip地址&#xff08;VIP&#xff1a;192.168.80.188&#xff09; 2.2 调整proc响应参数 2.3 设置负载分配策略 3、部署共享存储&#xff08;NF…

static详解

前言 大家好我是jiantaoyab&#xff0c;这篇文章来谈一谈c中的static&#xff0c;根据对static的使用&#xff0c;我分为类内和类外2种情况 static简介 static是c常用的修饰符&#xff0c;它用来控制变量的存储方式和可见性&#xff0c;在变量前面加上一个static&#xff0c…

ECMAScript 语法

ECMAScript 语法 一、ECMAScript1.ECMAScript简介2.ECMAScript历史 二、ECMAScript 语法区分大小写变量是弱类型的每行结尾的分号可有可无注释与 Java、C 和 PHP 语言的注释相同括号表示代码块 一、ECMAScript ECMAScript是一种由Ecma国际&#xff08;前身为欧洲计算机制造商协…

大唐杯学习笔记:Day6

1.1小区选择 一、概述 1.UE在RRC_IDLE和RRC——INACTIVATE状态下进行的过程&#xff1b; 2.UE首先需要完成PLMN的选择,在已选择的PLMN上寻找合适的小区,获取合适的服务,监听控制信道,这个过程即小区选择过程&#xff1b; 3.根据小区重选准则,UE寻找其他更适合的小区进行小区…

论文《Exploring CLIP for Assessing the Look and Feel of Images》阅读

论文《Exploring CLIP for Assessing the Look and Feel of Images》阅读 论文概述Preliminary方法论Experiments结论 论文概述 今天带来的是论文《Exploring CLIP for Assessing the Look and Feel of Images》&#xff0c;论文主要通过 CLIP 模型来完成图像的质量&#xff0…

js五星评价的制作方法

方法有两种&#xff0c;1、jquer插件&#xff1b;2、图片循环&#xff1b; 第一种、效果图 代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"…

一文了解 ArrayList 的扩容机制

了解 ArrayList 在 Java 中常用集合类之间的关系如下图所示&#xff1a; 从图中可以看出 ArrayList 是实现了 List 接口&#xff0c;并是一个可扩容数组&#xff08;动态数组&#xff09;&#xff0c;它的内部是基于数组实现的。它的源码定义如下&#xff1a; public class A…

通过hyperbeam创建梁单元截面属性

1、为模型中标准的圆柱形创建梁单元和赋予属性&#xff1b; 2、为模型中不标准的对称性实体创建梁单元和赋予属性&#xff1b; 3、为模型中壳体部分创建梁单元和赋予属性&#xff1b;

Linux系统之rename命令的基本使用

Linux系统之rename命令的基本使用 一、rename命令介绍二、raname工具版本2.1 C语言版本2.2 Perl版本 三、centos下的rename使用3.1 基本语法3.2 命令选项3.3 rename的基本使用 四、ubuntu下的rename使用4.1 基本语法4.2 命令选项4.3 rename命令的基本操作 五、rename注意事项 一…

“色狼”用英语怎么说?柯桥日常英语,成人英语口语学习

最近有粉丝问我"色狼"英文翻译是啥 首先声明不是"colour wolf"哈 关于“色狼”的英文表达有很多 快和C姐一起来看看吧&#xff01; 1.pervert 这个单词的意思是变态、色狼 是对性变态者最直观的描述 He is such a pervert&#xff01; I saw him lo…

学习基于 JavaScript 语言 的计算机界三大神书”之一 ——SICP

如何阅读“计算机界三大神书”之一 ——SICP 《计算机程序的构造和解释》&#xff08;Structure and Interpretation of Computer Programs&#xff0c;简记为SICP&#xff09;是MIT的基础课教材&#xff0c;出版后引起计算机教育界的广泛关注&#xff0c;对推动全世界大学计算…