【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. 效果图展示…

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

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

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

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

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…

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

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

【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 引发的数据倾斜 解决数据倾斜数…

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…

网络拓扑—FTP服务搭建

文章目录 FTP服务搭建网络拓扑配置网络FTPPC 安装FTP服务配置FTP服务FTP用户配置—1PC机访问FTP站点IE浏览器访问终端访问 FTP用户配置—2PC机访问ftp站点IE浏览器访问终端访问 FTP服务搭建 网络拓扑 //交换机忽略不计 FTP服务IP&#xff1a;192.168.1.1 PC机IP&#xff1a;19…

多级留言/评论的功能实现——Vue3前端篇

文章目录 思路分析封装组件父组件模板逻辑样式 子组件——二级留言模板逻辑样式 子组件——三级留言以上模板逻辑样式 留言组件的使用 写完论文了&#xff0c;来把评论的前端部分补一下。 前端的实现思路是自己摸索出来的&#xff0c;没找到可以符合自己需求的参考&#xff0c;…

windows 7 10 11快捷键到启动页面

1.快速打开用户启动文件夹 shell:startup 方式2&#xff1a;快速打开系统启动文件夹 shell:Common Startup shell:Common Startup

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO inline bazel增量编译

编译器 编译过程 compiling 动态链接库 Linking 接口ABI LTO PGO Theory Shared Library Symbol Conflicts (on Linux) 从左往右查找:Note that the linker only looks further down the line when looking for symbols used by but not defined in the current lib.Linux 下…

统计信号处理基础 习题解答10-4

题目&#xff1a; 重复习题10.3&#xff0c;但条件PDF变为&#xff1a; 以及均匀先验。如果非常大&#xff0c;这样先验知识很少&#xff0c;则会出现什么情况。 解答&#xff1a; 如果记 那么&#xff0c;根据条件独立性质&#xff0c;得到&#xff1a; 其中&#xff0c;&am…

SwiftUI中的组合动画(Simultaneous, Sequenced, Exclusive)

了解了常见的几种手势后&#xff0c;接下来我们了解一下组合手势的操作&#xff0c;当一个视图存在多个手势的时候&#xff0c;为了避免手势冲突&#xff0c;SwiftUI提供了自定义手势的方法&#xff0c;比如同时进行&#xff0c;顺序进行等等。 以下是一些常见的多种手势组合使…

关于AI绘画的模型、开源项目、工具、技巧的学习

目录 一、AI绘画的大模型有哪些&#xff1f; 二、Stable Diffusion是一个流行的AI绘画开源项目。 三、AI绘画的开源工具有哪些&#xff1f; 四、AI绘画的技巧 五、最简单的实践 一、AI绘画的大模型有哪些&#xff1f; AI绘画领域中存在多种大模型&#xff0c;每种模型都有…

渗透测试 一个很奇怪的支付漏洞

新手实战刷课网站、好玩又有趣&#xff01; 第一步 打开网站、任意账户名密码登陆发现验证码可重复利用 这时候我们可以试试admin账号、发现如果账号正确会提示账户已存在、反之回显账户密码错误 第二步 既然验证码可以重复利用&#xff1b;而且账号名有回显 这时候我们试…