
周测成绩出来后,Tyree看着自己电脑里存的成绩单,数字乱糟糟的:语文85、数学92、英语78、科学88……他自言自语:“要是能按分数排个序就好了,哪个最高、哪个最低一眼就能看出来。”
我说:“Python 里有现成的排序函数 sorted(),一行就能排好。但是,我们今天不直接用那个,而是自己动手写一个排序算法,看看电脑到底是怎么把数字排整齐的。”
他有点惊讶:“自己写?会不会很难?”
“不会。我们学最简单的‘冒泡排序’——就像水里的气泡,小的轻的往上冒,大的重的往下沉。你一听就懂。”
今天我们就来自己写一个排序程序。
看看怎么用循环比较相邻的数字,怎么交换它们的位置,最终让整个列表从小到大排好。
01
什么是冒泡排序?用扑克牌来比喻
你手里有一把乱序的扑克牌:[5, 2, 8, 1, 9]。你想把它们从小到大排好。
冒泡排序的做法是:
从左到右,比较相邻的两张牌。如果左边的比右边的大,就交换它们的位置。
这样一轮下来,最大的牌就会“沉”到最后面。
重复这个过程,只不过每一轮可以少比较一次(因为最后面的已经排好了)。
直到所有牌都排好。
这个过程就像气泡往上冒,所以叫“冒泡排序”。
02
先实现一次“比较并交换”
我们先用一个简单列表来演示。
numbers = [5, 2, 8, 1, 9]
我们要比较第0位和第1位:5 和 2。5 > 2,所以交换它们的位置。
在 Python 里,交换两个变量可以这样写:
a, b = b, a
对于列表里的两个位置:
numbers[0], numbers[1] = numbers[1], numbers[0]
现在我们来写一轮比较(从第0位到倒数第2位):

运行后,你会看到 [2, 5, 1, 8, 9]。最大的9已经沉到最后了。
len(numbers)- 1 是因为我们比较的是 i 和 i+1,如果 i 到最后一个,i+1 就越界了。
一次循环只能保证最大的数到末尾,但前面的还没有完全排好。
03
重复多轮,直到完全排好
我们需要重复这个过程,每一轮比较的次数少一次(因为末尾已经排好)。外面再套一层循环。

外层循环 j 从0到 n-1,表示最多需要 n 轮。
内层循环 range(n - 1 - j):第一轮 j=0,比较 n-1 次;第二轮 j=1,比较 n-2 次……因为每轮末尾已排好一个最大数。
当某一轮没有任何交换发生时,说明已经排好,可以提前结束,但这里为了简单,先跑满n 轮。
运行后,你会看到逐步排序的过程。
04
优化:提前结束排序
如果某一轮没有任何交换,说明整个列表已经有序,可以提前跳出循环。

这里swapped 记录这一轮是否有交换。如果没有,说明已经排好,break 跳出外层循环。
05
把冒泡排序封装成函数
以后我们想排序任何列表,可以这样写:
先定义bubble_sort(arr)

再来调入要排序的列表

注意:bubble_sort 会直接修改传入的列表。如果不想修改原列表,可以先复制一份:arr.copy()。
sorted_scores = bubble_sort(scores.copy()) 。
06
小项目:对水熊虫的存活天数排序
假设你记录了10只水熊虫的存活天数,想把它们从少到多排个序。

也是先调入 bubble_sort(arr)函数,再写排序的列表。
07
今天学到了什么
冒泡排序思想:重复比较相邻元素,把大的“沉”到底部。
两层循环:外层控制轮数,内层控制比较位置。
交换两个变量:a, b = b, a 非常方便。
优化:用 swapped 标志提前结束循环,提高效率。
封装成函数:方便重复使用。
Tyree看完自己写的排序函数,兴奋地说:“原来电脑是这样排队的!虽然 sorted() 一行搞定,但自己写出来更有成就感。”
numbers = [5, 2, 8, 1, 9]
# 调用 sorted(),传入列表
sorted_numbers = sorted(numbers)
print("排序后:", sorted_numbers) # 新列表:[1, 2, 5, 8, 9]
上面就是sorted()一行的写法。
第28课完成!
下一节课学习:二分查找——快速在有序列表里找到目标。
你会学到比“一个个找”快得多的查找方法,就像猜数字游戏里每次取中间值一样。
————热门推荐————
自学编程第27课:用 matplotlib 画柱状图,一眼看出哪种水熊虫活得最久
自学编程第8课:turtle画对称图形(彩色螺旋、彩色对称花、等边三角形、五角星)
自学编程第7课:turtle画图入门(画一个正方形,五角形,螺旋形,三角形)
自学编程第2课:用input让电脑问你名字(做一个打招呼程序)
自学编程第一步:安装Python和Thonny(零基础图文教程)
(本系列教程每天更新,欢迎关注)