【目录】
文章目录
【正文】
2. python 冒泡排序-全网最详细
学习时间:30分钟,难!
1. 什么是冒泡排序
冒泡排序(Bubble Sort)法可以理解成升序
排序,即排列顺序是由小到大
。
Bubble [ˈbʌbl]:冒泡。
Sort [sɔːt]:分类。
【实现原理】
从头开始比较每一对相邻
的元素,每一轮选出一个最大的数
放到序列最后
,重复遍历序列,直到完成升序排列。
这句话有3个重点:
- 从头开始
- 比较的是相邻的数
- 最大的数放到最后
之所以叫做冒泡排序,是因为每一个元素都可以像小气泡一样,根据自身大小一点一点向数组的一侧移动。
大的数向后移,小的数向前移。
冒泡排序的核心就是2个数相比较,大的数往后移
。
2. 实现过程分析
2.1 2个元素比较
a = [4,2]
对上面的列表进行冒泡排序,过程如下:
列表的第1个元素4
和第2个元素2
比较:4>2,交换位置,结果为[2,4]。
列表中最大的数4
已经排在最后,元素比较结束,冒泡排序完成。
【总结】
- 2个元素比较1次可完成升序排序。
- 列表元素的比较顺序如下:
- 0-1
【备注】
这里的0和1是列表的索引。
列表的索引0对应列表的第1个元素。
列表的索引1对应列表的第2个元素。
2.2 3个元素比较
a = [8,4,2]
第1轮排序,选出最大的数8
【第1次比较】
列表的起始顺序:[8,4,2]
第1个元素8
和第2个元素4
比较:8>4,交换位置,当前列表顺序[4,8,2]。
【第2次比较】
当前列表顺序[4,8,2]
新列表第2个元素8
和第3个元素2
比较:8>2,交换位置,当前列表顺序[4,2,8]。
此时,第一轮排序结束,选出最大的数8。
第2轮排序,选出最大的数4
【第3次比较】
第2轮排序时8已经是最大的数,位置固定,不在参与排序游戏。
当前列表顺序[4,2,8]
新列表的第1个元素4
和第2个元素2
比较:4>2,交换位置,当前列表顺序[2,4,8]。
【总结】
-
2个元素比较1次。
-
比较顺序如下:
-
0-1
-
3个元素比较3次。
-
比较顺序如下:
-
0-1
-
1-2
-
0-1
2.3 4个元素比较
a = [8,4,2,0]
第1轮排序,选出最大的数8
【第1次比较】
当前列表顺序:[8,4,2,0]
第1个元素和第2个元素比较:8>4,交换位置,当前列表顺序[4,8,2,0]。
【第2次比较】
当前列表顺序[4,8,2,0]
第2个元素和第3个元素比较:8>2,交换位置,当前列表顺序[4,2,8,0]。
【第3次比较】
当前列表顺序[4,2,8,0]
第3个元素和第4个元素比较:8>0,交换位置,当前列表顺序[4,2,0,8]。
4个元素经过3次循环可选出最大的数8。
8的位置固定不在参与排序游戏,还有3个数参与游戏。
第2次排序,选出第2大的数
【第4次比较】
3个数选出最大的数,需要2次比较。
当前列表顺序[4,2,0,8]
第1个元素和第2个元素比较:4>2,交换位置,当前列表顺序[2,4,0,8]。
【第5次比较】
当前列表顺序[2,4,0,8]
第2个元素和第3个元素比较:4>0,交换位置,当前列表顺序[2,0,4,8]。
此时4的位置固定,不再参与游戏。
第3次排序,选出第3大的数
【第6次比较】
2个数选出最大的数,只需1次比较。
当前列表顺序[2,0,4,8]
第1个元素和第2个元素比较:2>0,交换位置,当前列表顺序[0,2,4,8]。
每个数都找到自己的位置,游戏结束。
【总结】
-
2个元素比较1次。
-
比较顺序如下:
-
0-1
-
3个元素比较3次。
-
比较顺序如下:
-
0-1
-
1-2
-
0-1
-
4个元素比较6次。
-
比较顺序如下:
-
0-1
-
1-2
-
2-3
-
0-1
-
1-2
-
0-1
3. 课堂练习
请你思考5、6个元素分别需要比较几次,并写出列表的索引比较顺序。
冒泡排序就是每次选出一个最大的值,将最大值淘汰不参与剩下的游戏,因此每一轮循环淘汰1个元素:
2个元素的比较次数:1,循环1次
3个元素的比较次数:2+1 ,循环2次
4个元素的比较次数:3+2+1,循环3次
5个元素的比较次数:4+3+2+1,即循环4次
6个元素的比较次数:5+4+3+2+1 ,即循环5次
冒泡排序是从头开始比较,因此每一次循环比较都从索引0开始。
比较的是相邻的元素,因此后1个索引都比前1个索引多1。
每次都淘汰一个元素,因此每次都少一对索引比较。
因为每次循环只能选出一个最大的数,因此n个元素就需要循环n-1次。
- 5个元素比较10次。
- 比较顺序如下:
- 0-1
- 1-2
- 2-3
- 3-4
- 0-1
- 1-2
- 2-3
- 0-1
- 1-2
- 0-1
4. 循环代码
冒泡排序的代码难点在于循环的实现,下面我们先完成循环部分的代码。
像0-1,1-2,2-3
这样每个数都比前一个数多1的循环我们通常用一个for循环就能实现。
- 3个元素比较3次。
- 0-1
- 1-2
- 0-1
而像上面这样的上下2个数的值有增有减,我们通常考虑for循环嵌套。
- 0-1
- 1-2
前2行是递增的。
- 1-2
- 0-1
第2行到第3行是递减的。
有增又有减,那通常是用嵌套循环来实现的。
因为我们最终要编写自定义函数来实现冒泡排序,此时数组的元素个数是个动态值。
因此我们通常要将元素的个数加入for循环。
这种思路在实战中经常要用到。
【外循环】
2个元素的比较次数:1
3个元素的比较次数:2+1
4个元素的比较次数:3+2+1
5个元素的比较次数:4+3+2+1
6个元素的比较次数:5+4+3+2+1
- 3个元素比较3次。
- 0-1
- 1-2
- 0-1
我们以3个元素为例,3个元素比较3次,外循环可以先试写成如下代码:
# 这里的3是元素的个数:
for j in range(3):
print(j)
【终端输出】
0
1
2
【内循环】
-
3个元素比较3次。
-
0-1
-
1-2
-
0-1
-
0-1
-
1-2
第1次内循环要得到上面的数,需要循环2次,那range的值只能取到2,又同时需要把j的值带到内循环控制循环次数。
j=0的时候,3-j-1=2
我们可以先试着把循环代码写成下面这样:
# 这里的3是元素的个数:
for j in range(3):
for i in range(3-1-j):
print(i,i+1)
【终端输出】
0 1
1 2
0 1
【用4个元素检验循环代码】
# 这里的4是元素的个数:
for j in range(4):
for i in range(4-1-j):
print(i,i+1)
【终端输出】
0 1
1 2
2 3
0 1
1 2
0 1
【思路总结】
编写循环代码有以下几个要点:
- 通常需要把动态值加入range函数来控制循环次数。
- 需要查看规律确定外循环和内循环。
- 在不会分析规律的时候用简单的数字带入不断试错也能写出。
- 我现在也经常用数字带入试错的方法编写for循环。
5. 多个变量赋值
a = 3
b = 4
上面是我们学过的变量赋值法,每行代码给一个变量赋值。
为了使代码更简洁,Python也提供用一行代码完成多个变量的赋值。
a,b = 3, 4
print(a)
print(b)
【终端输出】
3
4
a,b = 3, 4
表示把3
赋值给变量a
,把值4
赋值给变量b
。
变量与变量之间,值与值之间用英文逗号,
分隔。
a,b,c= 3, 4, 5
print(a)
print(b)
print(c)
【终端输出】
3
4
5
【变量互换值】
a = 3
b = 4
a,b = b,a
print(a)
print(b)
【终端输出】
4
3
a的初始值是3,b的初始值是4。
a,b = b,a
表示把a b
的值互换。
a,b = b,a
等价于:
a=b
b=a
6. 元素交换
文章的开篇我们说过冒泡排序每一轮选出一个最大的数
放到序列最后
,那如何实现将元素放到最后的呢?
我们首先需要需要个if条件判断语句进行大小判断,如果前面的数大于后面的数那2个数通过变量赋值互换位置,如果小于等于则不执行互换位置代码。
【2个元素】
a = [4,2]
if a[0] > a[1]:
a[0],a[1]=a[1],a[0]
print(a)
【终端输出】
[2, 4]
【代码解析】
a = [4,2]
自定义一个列表,列表含有2个元素。
if a[0] > a[1]:
列表名[索引]
是列表索引取值法,根据列表的索引号取值。
a[0] 取到列表的第1个元素4
。
a[1] 取到列表的第1个元素2
。
如果列表的第1个元素的值大于第2个元素的值。
a[0],a[1]=a[1],a[0]
上面的代码实现了列表元素位置的互换。
如果列表的第1个元素的值大于第2个元素的值,
将原始列表a[1]的值赋值给新列表a[0]。
将原始列表a[0]的值赋值给新列表a[1]。
如果列表的第1个元素的值不大于第2个元素的值,
那后面的代码将不运行,列表的值不互换。
通过值的互换实现了元素位置互换。
7. 冒泡排序综合代码
【完整的冒泡排序代码示例】
def mao_pao(num_list):
num_len = len(num_list)
for j in range(num_len):
for i in range(num_len - 1 - j):
if a[i] > a[i+1]:
a[i], a[i+1] = a[i+1], a[i]
if __name__ == '__main__':
# 换成实际要排序的数组
a = [8,4,0,2]
mao_pao(a)
print(a)
【终端输出】
[0, 2, 4, 8]
【代码解析】
def mao_pao(num_list):
def
自定义一个函数- 函数名为
mao_pao
- 接收的参数为
num_list
,num_list
是实际要排序的数组,调用函数时要传入的参数。 - 注意自定义函数后需要跟一个英文冒号
:
num_len = len(num_list)
len
函数统计元素的个数,传入的是列表则统计的是列表的元素个数。num_len
就是代码元素个数。
for j in range(num_len):
外循环,控制循环的次数。
for i in range(num_len - 1 - j):
内循环,控制循环的比较次数。
if a[i] > a[i+1]:
a[i], a[i+1] = a[i+1], a[i]
-
if条件判断语句比较相邻两个元素的值。
-
如果结果是大于,2个元素互换位置。
-
结果是小于或等于,不执行元素互换位置的代码。
if __name__ == '__main__':
85. if name == "main"的作用和原理(适合小白)
a = [8,4,0,2]
这是要进行排序操作的对象。
mao_pao(a)
- 调用函数,
mao_pao
是函数名。 a
是要操作的对象,a
的值传递给自定义函数中的num_list
。
print(a)
最后输出排序后的列表。
为了方便初学者掌握运行过程,我多加2个print,代码如下:
【代码示例】
def mao_pao(num_list):
num_len = len(num_list)
for j in range(num_len):
for i in range(num_len - 1 - j):
if a[i] > a[i+1]:
a[i], a[i+1] = a[i+1], a[i]
# 输出进行比较的列表索引
print(i,i+1)
if __name__ == '__main__':
# 换成实际要排序的数组
a = [8,4,0,2]
mao_pao(a)
print("最终的排序结果:",a)
【终端输出】
0 1
1 2
2 3
0 1
1 2
0 1
最终的排序结果: [0, 2, 4, 8]
【代码示例】
def mao_pao(num_list):
x = 0
num_len = len(num_list)
for j in range(num_len):
for i in range(num_len - 1 - j):
if a[i] > a[i+1]:
a[i], a[i+1] = a[i+1], a[i]
x += 1
# 输出每一次排序后的列表
print(f"第{x}次排序结果",a)
if __name__ == '__main__':
# 换成实际要排序的数组
a = [8,4,0,2]
mao_pao(a)
print("最终的排序结果:",a)
【终端输出】
第1次排序结果 [4, 8, 0, 2]
第2次排序结果 [4, 0, 8, 2]
第3次排序结果 [4, 0, 2, 8]
第4次排序结果 [0, 4, 2, 8]
第5次排序结果 [0, 2, 4, 8]
第6次排序结果 [0, 2, 4, 8]
最终的排序结果: [0, 2, 4, 8]