【C语言】冒泡排序详解

前言

排序,就是将一组数据按特定的规则调换位置,使这组数据具有某种顺序关系,一般就是递增或递减。

在接触C语言不久,我们就会遇到其中一种有名的排序算法——“冒泡排序”,不知道你是否已经掌握了,如果还没有的话,不妨听一下我的讲解版本,或许能有一点启发。

记住,理解冒泡排序非常重要的一点是,你要知道这个名字“冒泡”并不是随便乱取的,通过画图你可以看到它的过程真的就像在“冒泡”,可以抓住这个形象的过程去理解。 当然冒泡可以向左冒,也可以向右冒。

讲解

实现冒泡的逻辑:

冒泡排序指的是在排序时,每次比较数组中相邻的两个数组元素的值,(假设我们现在要从小到大排序)如果前面的数大于后面的数,就将较小的数调换到较大的数前面。

现在我们假设有一组数据:7,6,14,5,2,如果用冒泡法对其进行排序,排成从小到大,那么每轮排序的过程我们可以画图:

图中下划线代表当下正在两两比较的两个数据。可以看到两两比较的结果就是14作为当前数组中最大的数被一路调换位置,到了数组的末尾位置(因为14作为数组最大的数,其实已经到了该到的位置,下一轮两两比较就与14无关了,它就像一个冒出当前范围的泡泡) 

以上是一轮冒泡,现在我们再看一轮:

此时可以看到,7被一路换到了14的前面也就是它应该到的位置,14则无需再进行比较,下一轮的7也无需再参与两两比较了。 

可以看到每一轮冒泡我们就能让一个数去到它该去的位置,也可以总结出一轮冒泡的规律:

冒泡排序每一轮冒泡就是一次整个数组的两两比较,规则很简单,两两比较所以会有是从数组第一个元素开始的,而当遍历到了最后一个元素就不会再往后遍历了因为已经没有元素了,而此时我们的前是到倒数第二个元素,所以我们可以得出每次冒泡(也就是每轮整个数组的两两遍历)的代码应该是:

int j = 0;
for (j = 0; j < sz - 1 - i; j++)//一会解释
{if (arr[j] > arr[j + 1])//如果“前”比“后”大,就交换{int tmp;//创建一个中间变量,用于交换tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}
}

在上面我们不断提到“”这个字眼,因为我们冒几次泡是需要确定的,上面代码中的for语句执行一次只能冒出一个泡泡,也就是只能让当前最大的数去到它应该去的位置,所以为了让所有数都去到应该取的位置,我们就需要将这个for语句循环sz-1次。sz-1是什么?

int arr[] = { 7,6,14,5,2 };
int sz = sizeof(arr) / sizeof(arr[0]);//数组元素个数

sz是数组元素个数,那么sz-1就是我们应该冒泡的轮数,因为当sz-1个元素都去到了该去的位置,剩下的那个也已经无需再排了。

所以我们现在再写一个外循环来控制上面这个负责两两比较的for循环的执行次数:

int i = 0;
for (i = 0; i < sz - 1; i++)
{int j = 0;for (j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){int tmp;tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}

那么,现在我来解释一下为什么内循环要写成for (j = 0; j < sz - 1 - i; j++),这个j < sz - 1 - i应该怎么理解呢?

我们上面说到,除了第一轮冒泡外,每一轮冒泡都有我们不去排的数,也就是先前已经排好了的数,上面第二轮冒泡我们不排的是14,第三轮冒泡我们不排的是14与7。这也说明我们每一轮冒泡需要两两比较的次数是不一样的,是变化的。而这个变化恰好就与我们的i变量有关,或者说恰好可以用变量i来表示:

如果没有-i,for (j = 0; j < sz - 1; j++)是什么效果?每一轮我们都会两两比较sz-1次,对于这个例子,5个元素,我们冒泡4轮,每一轮两两比较4次肯定是没必要的。

那for (j = 0; j < sz - 1 - i ; j++),带上-i后是什么效果? 第一轮冒泡,此时i为0,j<sz-1,也就是这一轮我们要两两比较4次,没错; 第二轮冒泡,此时i为1,j<sz-2,也就是两两比较3次,没错……最后一轮,此时i为sz-2也就是3,j<sz-4,也就是两两比较1次,没错。

所以可以看出,写成for (j = 0; j < sz - 1 - i ; j++)是非常正确的、符合预期的。

交换两个元素的值:

如果不理解交换两个元素的值的代码为什么这么写的读者,也可以再听一下解释:

int tmp;
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;

可能会有人好奇为什么不能写成:

arr[j] = arr[j + 1];
arr[j + 1] = arr[j];

这是初学C语言的我们确实可能会犯下的错,注意代码的执行顺序是从上到下,而arr[j] = arr[j + 1];的'='可不是等号,是赋值运算符所以当执行到arr[j + 1] = arr[j];的时候其实此时的arr[j]的值已经变为arr[j + 1]的值了,这相当于把arr[j + 1]的值再赋值给arr[j + 1],是不能达到我们预期的交换的效果的。

所以我们可以先把arr[j]的值赋给一个额外创建的变量tmp,将arr[j + 1] 的值赋给arr[j],要将arr[j]原本的值赋给arr[j + 1]时我们只用将tmp的值赋给arr[j + 1]就行了。

所以讲到这里,我们已经得出了冒泡排序的代码,我们可以将其封装成一个函数:

void bubble_sort(int* arr, int sz)//传过来的是数组名arr,是数组首元素地址,所以用整型指针接收arr//因为传过来的是数组首元素地址,所以不知道数组大小,所以要把元素个数一起传过来
{int i = 0;for (i = 0; i < sz - 1; i++){int j = 0;for (j = 0; j < sz - 1 - i; j++){if (arr[j] > arr[j + 1]){int tmp;tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}

相应的,main函数里应该是这样的:

int main()
{int arr[] = { 7,6,14,5,2 };int sz = sizeof(arr) / sizeof(arr[0]);//数组元素个数bubble_sort(arr,sz);//调用冒泡排序函数print(arr, sz);//排序完打印看看效果return 0;
}

这时可以看到我还写了一个函数print()专门用于打印数组,这样可以让我们的main函数更整洁,也可以提高复用性,下次打印就不用再写一次了,这是封装函数的好处,我们要尽早习惯这种做法。

//写一个函数实现对数组的打印
void print(int* arr, int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}

完整代码参考

vs运行效果:

 

可以看到我们的这组数据就成功地从小到大排序了。 

小结

我们可以总结出一些东西来帮助我们理解冒泡排序:

n个数冒泡排序,就要进行n-1轮冒泡;(第一轮n-1次两两比较)

对于我们的双层循环,i控制的是轮数,j才是负责控制两两比较的;

每轮要进行的两两比较是越来越少的,恰好可以用 j < sz - 1 - i表示;

每一轮冒泡,可以理解为把当前要比较范围内的最值一路冒到了最边上。

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

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

相关文章

【Go语言入门学习笔记】Part3.指针和运算符、以及基本输入

一、前言 仍然好多和C语言类似&#xff0c;计算机的学生应该是很容易入门这一环节&#xff0c;我还在最后的输入中看到了一些些Java输入的影子&#xff0c;而自动的变量类型推断更是有Python那个味道&#xff0c;正可谓几百家之所长了。 二、学习代码 package mainimport (&q…

鸿蒙系统和安卓系统通过termux搭建Linux系统—Centos

目录 1. 前言 2. 效果图展示 3. 安装termux 4. 安装Centos系统 4.1 更换源 4.2 拉取镜像 4.3 启动centos 5.结尾 1. 前言 大家好&#xff0c;我是jiaoxingk 今天这篇文章让你能够在手机或者平板上使用Linux-Centos系统 让你随时随地都能操作命令行进行装13 2. 效果图展示…

节省时间与精力:用BAT文件和任务计划器自动执行重复任务

文章目录 1.BAT文件详解2. 经典BAT文件及使用场景3. 使用方法4. 如何设置BAT文件为定时任务5. 实例应用&#xff1a;自动清理临时文件 BAT文件&#xff0c;也就是批处理文件&#xff0c;是一种在Windows操作系统中自动执行一系列命令的文本文件。这些文件的扩展名为 .bat。通过…

[力扣题解] 1971. 寻找图中是否存在路径

题目&#xff1a;1971. 寻找图中是否存在路径 思路 并查集 代码 class Solution { private:int n 200005;int father[200005] {0};void init(){int i;for(i 0; i < n; i){father[i] i;}}int find(int u){if(u father[u]){return u;}else{return father[u] find(fa…

就业班 第三阶段(CICD) 2401--5.15 day2 自动化构建打包、部署(Jenkins + maven+ gitlab+tomcat)

一、平滑发布与灰度发布 **什么叫平滑&#xff1a;**在发布的过程中不影响用户的使用&#xff0c;系统不会因发布而暂停对外服务&#xff0c;不会造成用户短暂性无法访问&#xff1b; **什么叫灰度&#xff1a;**发布后让部分用户使用新版本&#xff0c;其它用户使用旧版本&am…

golang内置模块os常用操作函数 按功能分类整理

go语言中我们最常用的一个内置模块os模块&#xff0c;这个里面的函数虽然很多&#xff0c;但是分类整理后其实也就环境变量&#xff0c;用户&#xff0c;目录&#xff0c;文件进程和错误类型这几类&#xff0c;本文按照功能分类整理方便记忆和使用。 func Exit(code int) 退出当…

【吊打面试官系列】Java高并发篇 - ReadWriteLock 是什么 ?

大家好&#xff0c;我是锋哥。今天分享关于 【ReadWriteLock 是什么 &#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; ReadWriteLock 是什么 &#xff1f; 首先明确一下&#xff0c;不是说 ReentrantLock 不好&#xff0c;只是 ReentrantLock 某些时候有局限。 …

Excel工作表单元格单击选中事件,VBA动态计算同类数值总和

Excel工作表单元格单击选中事件,VBA动态计算同类数值总和(VX公众号:Excel潘谆白说VBA) 文章目录 前言一、运行效果二、代码前言 面对每月的消费账单,面对月底待还的信用卡或花呗,面对不足三位数的余额,你是否怀疑过账单自己的消费。你是否因此开始记账,每个月记流水,想知…

2024/5/22 学习杂记

为什么功率放大电路在模电中经常提到&#xff1f; 模拟信号&#xff1a;它是连续变化的电信号&#xff0c;它在时间上和幅度上都是连续的&#xff0c;能够代表信息的连续变化。大多数物理量为模拟信号&#xff0c;如&#xff1a;温度、压力、流量… 非电物理量通过传感器变换成…

鸿蒙 DevEcoStudio:发布进度条通知

使用notificationManager及wantAgent实现功能import notificationManager from ohos.notificationManager import wantAgent from ohos.app.ability.wantAgent Entry Component struct Index {State message: string 发布进度条通知progressValue: number0async publicDownloa…

基于DdddOcr通用验证码离线本地识别SDK搭建个人云打码接口Api

前言 最近介绍了一款免费的验证码识别网站,识别效率太低,考虑到ddddocr是开源的,决定搭建搭建一个,发现原作者sml2h3已经推出好久了,但是网上没有宝塔安装的教程,于是本次通过宝塔搭建属于自己的带带弟弟OCR通用验证码离线本地识别 原项目地址:https://github.com/sml2…

过滤器 -- Filter

ActionFilterAttribute: 示例:实现一个日志记录过滤器,记录每个控制器动作方法的执行时间和参数信息。 public class LogActionFilterAttribute : ActionFilterAttribute {public override void OnActionExecuting(ActionExecutingContext context){// 记录方法开始执行时间和参…

Serverless应用引擎SAE评测|一分钟部署在线游戏

Serverless应用引擎SAE评测|一分钟部署在线游戏 什么是Serverless应用引擎SAE一分钟部署在线游戏SAE控制台 资源释放其他操作 在进行Serverless应用引擎SAE评测之前&#xff0c;首先需要了解一下什么是SAE。 什么是Serverless应用引擎SAE Serverless应用引擎SAE&#xff08;Se…

代码随想录-算法训练营day50【动态规划12:最佳买卖股票时机含冷冻期、买卖股票的最佳时机含手续费、股票问题总结】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第九章 动态规划part12● 309.最佳买卖股票时机含冷冻期 ● 714.买卖股票的最佳时机含手续费 ●总结309.最佳买卖股票时机含冷冻期 本题加了一个冷冻期,状态就多了,有点难度,大家要把各个状态分清,思路才能清晰…

【EXCEL_VBA_基础知识】15 使用ADO操作外部数据

课程来源&#xff1a;王佩丰老师的《王佩丰学VBA视频教程》&#xff0c;如有侵权&#xff0c;请联系删除&#xff01; 目录 1. 使用ADO链接外部数据源 2. 常用SQL语句&#xff08;Execute(SQL语句)&#xff09; 2.1 查询数据、查询某几个字段、带条件查询、合并两表数据、插…

手把手教你解决 Hive 的数据倾斜

文章目录 数据倾斜是什么&#xff1f;产生数据倾斜的场景1.空值引发的数据倾斜2.不可拆分的大文件产生的数据倾斜3.数值膨胀引发的数据倾斜4.不同数据类型引发的数据倾斜5.Count(distinct) 引发的数据倾斜6.表 Join 操作时引发数据倾斜7.group by 引发的数据倾斜 解决数据倾斜数…

easyswoole3.5 redis使用

安装redis指定版本 composer require easyswoole/redis:^1.3 redis配置&#xff0c;dev.php <?phpuse EasySwoole\Log\LoggerInterface;return [SERVER_NAME > "EasySwoole",MAIN_SERVER > [LISTEN_ADDRESS > 0.0.0.0,PORT > 9503,SERVER_TYPE &g…

MySQL之性能剖析(三)

剖析MySQL查询 剖析单条查询 在定位到需要优化的单条查询后&#xff0c;可以针对查询"钻取"更多的信息&#xff0c;确认为什么会花费这么长的时间执行&#xff0c;以及需要如何去优化。不幸的是&#xff0c;MySQL目前大多数的测量点对于剖析查询都没有什么帮助。当…

Python | Leetcode Python题解之第100题相同的树

题目&#xff1a; 题解&#xff1a; class Solution:def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:if not p and not q:return Trueif not p or not q:return Falsequeue1 collections.deque([p])queue2 collections.deque([q])while queue1 and queue2:node…