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

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

1:主函数,创建数组

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

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

4:交换数据

5:写交换结果

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

剑指offer刷题记录Day2 07.数组中重复的数字 ---> 11.旋转数组的最小数字

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、重建二叉树①代码实现&#xff08;带注释&am…

MQL5学习之简单移动平均线MA的编写

昨天还是有点高估自己了&#xff0c;MACD相对较难一点&#xff0c;改学MA的编写&#xff0c;首先明确MA的计算&#xff0c;假如有4个值&#xff0c;p[1&#xff0c;2&#xff0c; 3&#xff0c; 4], period3, 则v[0]p[0], v[1]p[1],v[2](p[0]p[1]p[2])/32, v[3](v[2]*3p[3]-p…

rust多个mod文件引用和文件夹mod使用注意事项

如果mod文件都在同一级目录&#xff0c;则直接使用就可以&#xff0c;因为rust文件都是一个隐藏的mod&#xff0c;但是如果mod文件在另外一个目录下面&#xff0c;就需要在目录下面声明一个mod.rs文件&#xff0c;这样才能将那个目录识别为一个mod&#xff0c;可以在mod.rs里面…

分布式事务详解-高频面试题

分布式事务都有哪些 其实说到分布式事务 我们不得不提事务的分类 事务可以分为本地事务&#xff0c;和分布式事务&#xff0c; 本地事务就是单体系统下基于数据库的ACID来实现的事务&#xff0c;而分布式事务是指在分布式环境下保证多个系统事务一致性的问题 而分布式事务 其…

初阶数据结构之---栈和队列(C语言)

引言 在顺序表和链表那篇博客中提到过&#xff0c;栈和队列也属于线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连…

Java项目:33 基于Java Web的网上拍卖系统(含源码数据库+文档免费送)

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 主要功能包括&#xff1a; 1.前台模块 &#xff08;1&#xff09;普通用户登录/注册。 &#xff08;2&#xff09;分类查看商品(普通商品与促销商品…

集成2.5G/5G/10G高速率网络变压器的RJ45网口连接器产品特点介绍

Hqst华轩盛(石门盈盛)电子导读&#xff1a;集成2.5G/5G/10G高速率网络变压器的RJ45网口连接器产品特点介绍&#xff1a; 第一、 高速率&#xff1a;支持高达2.5Gbps、5Gbps和10Gbps的传输速率&#xff0c;能够满足高带宽的网络应用需求。 第二、 集成2.5G/5G/10G高速率网…

【C++】set、multiset与map、multimap的使用

目录 一、关联式容器二、键值对三、树形结构的关联式容器3.1 set3.1.1 模板参数列表3.1.2 构造3.1.3 迭代器3.1.4 容量3.1.5 修改操作 3.2 multiset3.3 map3.3.1 模板参数列表3.3.2 构造3.3.3 迭代器3.3.4 容量3.3.5 修改操作3.3.6 operator[] 3.4 multimap 一、关联式容器 谈…

Vue开发实例(五)修改项目入口页面布局

修改项目入口 一、创建新入口二、分析代码&#xff0c;修改入口三、搭建项目主页面布局1、Container 布局容器介绍2、创建布局3、布局器铺满屏幕4、创建Header页面5、加入Aside、Main和Footer模块 一、创建新入口 创建新的入口&#xff0c;取消原来的HelloWorld入口 参考代码…

测试需求平台9-Table 组件应用产品列表优化

✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版&#xff0c;拥抱Vue3.0将前端框架替换成字节最新开源的arco.design&#xff0c;其中约60%重构和20%新增内容&#xff0c;定位为从 0-1手把手实现简单的测试平台开发教程&#xff0c;内容将囊括基础、扩展和实战&a…

文件操作和IO(2):Java中操作文件

目录 一、File的属性 二、File的构造方法 三、File的方法 四、代码示例 1、getName&#xff0c;getParent&#xff0c;getPath方法 2、getAbsolutePath&#xff0c;getCanonicalPath方法 3、exists&#xff0c;isDirectory&#xff0c;createNewFile方法 4、createNewF…

【04】C语言括号匹配问题

欢迎来到土土的博客~&#x1f973;&#x1f973;&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1f4a5; 所属专栏&#xff1a;C语言系列函数实现 题目描述&#xff1a; 给定一个只包括 ‘(’&#xff0c;‘)’&#xf…

金融业被网络攻击了怎么办,如何治理和风险控制?

近年来&#xff0c;网络罪犯的人数和复杂程度都在增加&#xff0c;网络罪犯的目标锁定变得更具策略性&#xff0c;更加专注于最大效率和获利。随着有关全球网络犯罪的数据持续涌入&#xff0c;可以看出金融服务企业已然成为头号锁定目标。虽然金融服务企业在网络安全人员、工具…

python 基础知识点(蓝桥杯python科目个人复习计划57)

今日复习计划&#xff1a;做题 例题1&#xff1a;笨笨的机器人 问题描述&#xff1a; 肖恩有一个机器人&#xff0c;他能根据输入的指令移动相应的距离。但是这个机器人很笨&#xff0c;他永远分不清往左边还是往右边移动。肖恩也知道这一点&#xff0c;所以他设定这个机器人…

实现数组方法 forEach map filter every

手写forEach Array.prototype.myforEach function (fn, thisValue) {let index 0;let arr thisValue || this;if (typeof fn ! function) {throw new TypeError(fn is not a function)}while (index < arr.length) {if (index in arr) {fn.call (thisValue, arr[index],…

AI入门笔记(三)

神经网络是如何工作的 神经网络又是如何工作的呢&#xff1f;我们用一个例子来解释。我们看下面这张图片&#xff0c;我们要识别出这些图片都是0并不难&#xff0c;要怎么交给计算机&#xff0c;让计算机和我们得出同样的结果&#xff1f;难点就在于模式识别的答案不标准&…

Mybatis_plus-逻辑删除、通用枚举、自动填充、插件等

一、逻辑删除 曾经我们写的删除代码都是物理删除。 逻辑删除&#xff1a;删除转变为更新 ​ update user set deleted1 where id 1 and deleted0 查找: 追加 where 条件过滤掉已删除数据,如果使用 wrapper.entity 生成的 where 条件也会自动追加该字段 ​ 查找: select id,nam…

【NR 定位】3GPP NR Positioning 5G定位标准解读(五)

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

扑克牌翻牌记忆小游戏源码

源码由HTMLCSSJS组成&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 效果预览 下载地址 https://www.qqmu.com/2296.html

Spring学习笔记(七)SpringMVC入门

一.什么是Spring MVC 1.什么是MVC&#xff08;一种思想模式&#xff09; M:模型 V:视图 C:控制器 2、Java EE三层架构 在Java EE开发中&#xff0c;系统经典的三层架构包括表现层、业务层和持久层。 表现层&#xff08;Web层&#xff09;负责接收客户端请求&#xff0c;并…
最新文章