📄 一句话概括
冒泡排序:相邻两个比一比、大的往右换,每一轮【最大的泡泡】沉到队尾;摇晃排序(Shaker Sort,又称鸡尾酒排序、双向冒泡):冒泡的改良——来回双向扫,对【基本有序】的数据快得多。
📝 本节和前面几节的关系
4-11 的选择/插入是【挑与插】,这一对的灵魂是【相邻交换】。回收 4-11 的 O(n²) 与【基本有序】话题——摇晃排序正是冲着这个短板来的改良。
一、冒泡:相邻交换、大的沉底
[5, 3, 8, 1, 9, 2] 从左往右逐对比较、大的往右换
第一轮:5>3 换 -> 3,5,8...;8>1 换 -> 9 沉底 ...
第一轮结束:9 已在最右(最大的泡泡先浮出)
第二轮:对剩下前 5 个再来一遍 -> 8 沉到倒数第二 ...
b = [5, 3, 8, 1, 9, 2]
for i in range(len(b) - 1): # 共 n-1 轮
swapped = False
for j in range(len(b) - 1 - i): # 每轮少比一个(尾部已就位)
if b[j] > b[j + 1]:
b[j], b[j + 1] = b[j + 1], b[j]
swapped = True
if not swapped: # 整轮没换过 = 已经有序,提前收工
break
print(b) # [1, 2, 3, 5, 8, 9]
两个标配优化:每轮缩短比较范围(尾部已排好)+ swapped 标志(没换就提前停)。加上后者,冒泡对【已有序】数据是 O(n);乱数据仍是最坏 O(n²)。
二、摇晃排序:来回双向扫
冒泡的盲区:小的沉不下来——每轮只保证大的往右挪,左边的小乌龟(如最后的 1)每次只能挪一格。摇晃排序(Shaker/鸡尾酒/双向冒泡)一轮干两件事:先从左往右冒(大数沉底),再从右往左扫(小数浮头)——乌龟坐上回程快车:
[2, 3, 4, 5, 1] 只有 1 错位
冒泡:要 4 轮(1 每轮挪一格)
摇晃:第 1 轮正向(5 沉底)+反向(1 一次漂到最左)——1~2 轮搞定
c = [2, 3, 4, 5, 1]
lo, hi = 0, len(c) - 1
while lo < hi:
swapped = False
for j in range(lo, hi): # 正向:大的沉底
if c[j] > c[j + 1]:
c[j], c[j + 1] = c[j + 1], c[j]
swapped = True
hi -= 1
for j in range(hi, lo, -1): # 反向:小的浮头
if c[j] < c[j - 1]:
c[j], c[j - 1] = c[j - 1], c[j]
swapped = True
lo += 1
if not swapped:
break
print(c) # [1, 2, 3, 4, 5]
性格:最坏仍 O(n²),两端夹击使扫描区间双向收缩——对【部分有序】数据轮数减半以上;代码复杂度比冒泡高一档,实战性价比一般,但【改良思路】极经典。
三、动手 Demo:乌龟现形
def bubble(arr):
b = arr.copy()
for i in range(len(b) - 1):
for j in range(len(b) - 1 - i):
if b[j] > b[j + 1]:
b[j], b[j + 1] = b[j + 1], b[j]
return b
data = [2, 3, 4, 5, 1]
print(bubble(data)) # [1, 2, 3, 4, 5] —— 结果一样
读结果:结果与摇晃排序相同——差别在过程:冒泡的 1 要走 4 格(每轮一格),摇晃的 1 一轮直达。拿 4-11 的插入排序比同一条数据:一次插入直接到位——三种算法、同一结果、路径各不同。
四、30 秒实验
在冒泡的内层循环里加一行 print(b)(每轮打印),拿 [2, 3, 4, 5, 1] 跑一遍——亲眼看 1 每轮只挪一格(乌龟)。这 30 秒的动画感,胜过文字十遍。
五、常见误区
- 【摇晃排序复杂度比冒泡低一个档次】——错。最坏仍是 O(n²);它改良的是常数与【部分有序】场景的轮数,不是复杂度档位。
- 【加了 swapped 的冒泡就是 O(n)】——只对【已有序/基本有序】成立;乱数据照样两两比、O(n²)。
- 【这些 O(n²) 排序实际项目没人用】——半错。直接手写确实少(Python 用 sorted);但小数据、教学、嵌入式极端受限环境里它们仍出场,且是理解 4-13 高速排序的地基。
自测三问(点开对答案)
1. **冒泡排序每轮结束能保证什么?** 答:当前未排序段的最大值沉到段尾——每轮至少【钉死】一个元素的最终位置。 2. **摇晃排序改良了冒泡的什么短板?** 答:小元素(乌龟)每轮只能挪一格的问题——反向扫描让小数一次漂到最左,双向收缩区间。 3. **swapped 标志的作用?** 答:整轮无交换说明已有序,提前退出——对已有序数据从 O(n²) 降到 O(n)。- ☐ 下一节(4-13 合并排序、快速排序)
相关笔记
- 选择与插入排序 —— 同门的另外两员
- 归并与快排 —— O(n log n) 的正主
- 时间复杂度与大 O —— 为什么 O(n²) 是慢档
- ⌨️ 编程原理 · 索引 —— 全课路线图