如此简单的冒泡排序,我居然不知道这个原理?

本文深入浅出地介绍了冒泡排序的实现原理与代码实现过程,通过生动的GIF图和详细的步骤解析,帮助读者理解冒泡排序的工作机制。同时,提供了完整的C语言代码示例,演示了如何使用冒泡排序对数组进行排序。

引言

算法,是大多数小白的噩梦。它时常让众多小白们琢磨不透。对于初学者来说,即使是最基础的算法,也要转很久的弯才能绕过来,但是过了几天,又遗忘得差不多。当老师布置一道算法题的时候……
甲:今天怎么又要写算法了?
乙:这什么破题!码字10分钟,调试一小时。
丙:大神救我!算法题鲨我!!!
丁:真是一窍不通,选错专业了呜呜呜。
在这里插入图片描述
但是,无论算法有多么难,都要保持着一颗真诚的心。
算法虐我千百遍,我待算法如初恋。
在做算法题的时候,你的表情应该是这样子的。
在这里插入图片描述
在跟同学一起交流学习的时候,是不是经常发现,自己好不容易研究出一道算法题跟同学分享后,瞬间逼格满满。
当同学们看到你的运行结果后……
在这里插入图片描述
但是,做出一道算法题并不说明你很厉害。
殊不知,这才是身经百战的算法大佬!
在这里插入图片描述
咳咳咳,废话说多了,言归正传,现在教教大家如何实现数组排序!这种算法是展现逼格的第一层内功!

一、实现原理详解

原理暂时先不多说,一张 gif 图先干为敬!看看能不能理解!
在这里插入图片描述
大家看出来了吗?
比如说有一组数组20 10 15 30 12
我们要把它从小到大排列,如果抛开代码实现的话,怎么排序?大家可以在纸上手写感受一下!
步骤如下:
(1)第一轮比较
①20 和 10 比较,即第一个和第二个比较,显然第二个更小,我们就把10放在前面,20放在后面。
这样原来的数组就变成 10 20 15 30 12
②20 和 15 比较,即第二个和第三个比较,显然15更小,把15放在20前面。
这样原来的数组就变成 10 15 20 30 12
③20 和 30 比较,即第三个和第四个比较,显然20更小,20位置就不用变了。
这样数组还是 10 15 20 30 12
④30 和 12 比较,即第四个和第12个比较,显然12更小,把12放在30前面。
这样数组变为 10 15 20 12 30

看到没,步骤①到步骤④遍历了所有的数,每次都把相邻的数进行比较和交换。这是第一轮比较!

(2)第二轮比较:重复第一轮比较的步骤
最终所得数组为 10 15 12 20 30
仔细看看,嗯,还是没完成从小到大排列,继续继续!
(3)第三轮比较:重复第一轮比较的步骤
最终所得数组为 10 12 15 20 30
哈哈哈,发现了没,它现在已经是从小到大排列了!

二、代码实现详解

接下来,装逼的时刻到了,我们要把冒泡排序算法用C语言代码来实现!
在这里插入图片描述
不懂的同伴,可以一边看讲解,一边对应代码。
冒泡排序代码详解:第⑤步是冒泡排序的关键。源码下滑可得
①main()函数进入程序,首先是声明i,j,t,这三个变量刚开始看的时候可能没看懂,先跳过
②又声明了一个数组a,长度为10
③关键来了,srand()函数是啥东西?它存在于<stdlib.h>头文件中,定义为void srand(unsigned int seed),在本程序中seed对应time(0),用来初始化随机数发生器,简单地来说,在进行任何取随机数操作之前,都要有**srand()**函数的调用。
④分别给数组中的每个数赋予随机值并打印,随机值的范围在60~100之间
60~100在代码中要写成60+40*rand()/RAND_MAX

for(i=0;i<10;i++){
		a[i]=(int)(60+40*rand()/RAND_MAX);
		printf("%5d",a[i]);
	}

⑤第五步是是冒泡排序的核心
我不知道大家是否能看懂这段代码,但是实现冒泡排序的排序过程,确实只要这一段代码足以。
for(i=0;i<9;i++):
for(j=0;j<9-i;j++)
冒泡排序的实现要用两个for的嵌套循环
比如有一个长度为10数组,要进行9轮的排序,每轮都遍历所有数,这是 i<9 的含义;
细心的朋友会发现,每进行一轮排序之后,下一轮排序的次数就减少了一次,这是就是 j<9-i 的由来
在长度为10的数组中,第一轮排序排列 9 次,第二轮排序就排8次,依次类推,第9轮排序只排一次
在冒泡排序中,一个数组排序的轮数永远是
其长度的值减去1

if(a[j]>a[j+1]){
int t;
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}

相邻两个数,若前一个数大于后一个数,则两个数的值进行置换!

⑥输出冒泡排序后的数组


for(i=0;i<9;i++)
		for(j=0;j<9-i;j++)
		if(a[j]>a[j+1]){
			int t;
			t=a[j];
			a[j]=a[j+1];
			a[j+1]=t;
		}

三、冒泡排序完整代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(){
	int i,j,t;
	int a[10];
	srand((int)time(0));
	printf("The score of the singers:\n");
	for(i=0;i<10;i++){
		a[i]=(int)(60+40*rand()/RAND_MAX);
		printf("%5d",a[i]);
	}
	printf("\n");
	for(i=0;i<9;i++)
		for(j=0;j<9-i;j++)
		if(a[j]>a[j+1]){
			int t;
			t=a[j];
			a[j]=a[j+1];
			a[j+1]=t;
		}
	printf("The sorted scores:\n");
	for(i=0;i<10;i++)
		printf("%5d",a[i]);
	return 0;
}
<think>我们被要求解释冒泡排序算法的工作原理和实现逻辑。根据引用[1]中的描述,冒泡排序是排序算法中基础且重要的一种,以其简洁易懂著称。下面将详细说明其工作原理。 ### 冒泡排序的工作原理 冒泡排序的基本思想是重复遍历待排序的列表,比较相邻的两个元素,如果它们的顺序错误(即前一个比后一个大,在升序排序中)就交换它们。通过多次遍历,每次遍历都会将当前未排序部分的最大(或最小)元素“冒泡”到正确的位置。具体过程如下: 1. **比较相邻元素**:从列表的第一个元素开始,比较相邻的两个元素(第1个和第2个,第2个和第3个,依此类推)。 2. **交换位置**:如果第一个元素比第二个元素大(升序排序),则交换这两个元素的位置。 3. **一轮遍历**:对每一对相邻元素做同样的工作,从开始第一对到最后一对。这样,一轮遍历结束后,最大的元素就会“冒泡”到列表的最后一个位置。 4. **重复过程**:重复上述过程,每次遍历都会将剩余未排序元素中的最大值放到正确的位置。每次遍历的元素数量比上一次少一个(因为每次遍历后,最后的元素已经有序)。 5. **终止条件**:当一轮遍历中没有发生任何交换时,说明列表已经有序,排序结束。 ### 实现逻辑 在实现上,冒泡排序使用两层循环: - **外层循环**:控制排序的轮数,共进行 $n-1$ 轮($n$ 是列表长度),因为每次将一个元素放到正确位置,共需 $n-1$ 次。 - **内层循环**:负责每一轮的具体比较和交换。内层循环的范围是从第一个元素到未排序部分的最后一个元素(即每轮循环次数为 $n-i$,其中 $i$ 是当前轮数,从1开始)。 ### 示例(升序排序) 假设有一个数组:$[5, 3, 8, 6, 7, 2]$,共6个元素。 **第一轮遍历**: - 比较5和3:5>3,交换 → [3,5,8,6,7,2] - 比较5和8:5<8,交换 → [3,5,8,6,7,2] - 比较8和6:8>6,交换 → [3,5,6,8,7,2] - 比较8和7:8>7,交换 → [3,5,6,7,8,2] - 比较8和2:8>2,交换 → [3,5,6,7,2,8] → 第一轮结束,最大数8已到末尾。 **第二轮遍历**: - 比较3和5:3<5,交换 → [3,5,6,7,2,8] - 比较5和6:5<6,交换 → [3,5,6,7,2,8] - 比较6和7:6<7,交换 → [3,5,6,7,2,8] - 比较7和2:7>2,交换 → [3,5,6,2,7,8] → 第二轮结束,7已到正确位置。 如此继续,直到整个数组有序。 ### 优化 可以设置一个标志位来检测某一轮是否发生交换,如果没有交换,说明数组已经有序,可以提前终止排序,减少必要的循环。 ### 时间复杂度 - 最坏情况(逆序数组):$O(n^2)$ - 平均情况:$O(n^2)$ - 最好情况(已有序):$O(n)$(使用优化后,只需要一轮遍历) ### MATLAB 实现(带优化) 以下是带优化的冒泡排序MATLAB实现: ```matlab function sorted_array = bubble_sort_optimized(arr) n = length(arr); for i = 1:n-1 swapped = false; % 标志位,记录本轮是否发生交换 for j = 1:n-i if arr(j) > arr(j+1) % 交换相邻元素 temp = arr(j); arr(j) = arr(j+1); arr(j+1) = temp; swapped = true; % 标记发生交换 end end % 如果没有发生交换,提前结束 if ~swapped break; end end sorted_array = arr; end ``` ### 总结 冒泡排序通过断比较相邻元素并交换位置,使较大的元素逐渐“冒泡”到数组的末端。虽然效率高,但实现简单,是理解排序算法的基础[^1]。 --- 相关问题: 1. 冒泡排序在最好情况下的时间复杂度是多少? 2. 如何用C语言实现冒泡排序算法? 3. 冒泡排序和选择排序有哪些区别? 4. 为什么冒泡排序在实际应用中较少使用?</think>### 冒泡排序算法的工作原理 冒泡排序是一种基于比较的简单排序算法,其核心原理是**重复遍历列表,通过相邻元素的比较和交换,将最大(或最小)元素逐步“冒泡”到正确位置**。具体工作流程如下: 1. **相邻元素比较**: - 从列表第一个元素开始,比较相邻的两个元素($a_j$ 和 $a_{j+1}$) - 如果顺序错误($a_j > a_{j+1}$ 升序时),则交换它们的位置 - 比较操作持续进行到列表末尾 2. **元素“冒泡”过程**: - 每完成一轮遍历,当前未排序部分的最大元素会“冒泡”到正确位置 - 下一轮遍历时,比较范围缩小一位(已排序部分再参与比较) 3. **终止条件**: - 当某轮遍历中未发生任何交换时,说明列表已完全有序 - 算法立即终止(可通过标志位优化实现) 用数学表达式描述排序过程: $$ \text{第 } k \text{ 轮排序后:} \underbrace{a_1 \leq \cdots \leq a_{n-k}}_{\text{未排序部分}} \leq \overbrace{a_{n-k+1} \leq \cdots \leq a_n}^{\text{已排序部分}} $$ ### 实现逻辑(MATLAB 伪代码) ```matlab function sorted = bubbleSort(arr) n = length(arr); for i = 1:n-1 % 外层循环控制轮数 swapped = false; % 交换标志位(优化) for j = 1:n-i % 内层循环遍历未排序部分 if arr(j) > arr(j+1) % 交换相邻元素 [arr(j), arr(j+1)] = deal(arr(j+1), arr(j)); swapped = true; end end if ~swapped % 提前终止检查 break; end end sorted = arr; end ``` ### 算法特性 | 特性 | 说明 | |--------------|-------------------------------| | **时间复杂度** | 最坏 $O(n^2)$,最好 $O(n)$(优化后) | | **空间复杂度** | $O(1)$(原地排序) | | **稳定性** | 稳定(相等元素交换) | | **适用场景** | 小规模数据或基本有序列表 | ### 排序过程示例 以数组 $[5, 3, 8, 2]$ 升序排序为例: 1. **第一轮**: - 比较 5>3 → 交换 → [**3**, **5**, 8, 2] - 比较 5<8 → 保持 → [3, 5, 8, 2] - 比较 8>2 → 交换 → [3, 5, **2**, **8**](最大元素8到位) 2. **第二轮**: - 比较 3<5 → 保持 → [3, 5, 2, 8] - 比较 5>2 → 交换 → [3, **2**, **5**, 8](次大元素5到位) 3. **第三轮**: - 比较 3>2 → 交换 → [**2**, **3**, 5, 8](排序完成) > 注:实际实现中可通过标志位在第二轮后提前终止[^1]。 --- ### 相关问题: 1. 冒泡排序在最好情况下的时间复杂度如何达到 $O(n)$? 2. 如何用 Python 实现带优化的冒泡排序算法? 3. 冒泡排序与插入排序在性能上有哪些差异? 4. 为什么冒泡排序在实际应用中较少用于大规模数据?
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶叶扁舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值