冒泡排序:Python语言实现
冒泡排序多次遍历列表。它比较相邻的元素,将不合顺序的交换。每一轮遍历都将下一个最 大值放到正确的位置上。本质上,每个元素通过“冒泡”找到自己所属的位置。
下图展示了冒泡排序的第一轮遍历过程。深色的是正在比较的元素。如果列表中有 n 个元素,那么第一轮遍历要比较 n–1 对。注意,最大的元素会一直往前挪,直到遍历过程结束。
第二轮遍历开始时,最大值已经在正确位置上了。还剩 n–1 个元素需要排列,也就是说要比较 n–2 对。既然每一轮都将下一个最大的元素放到正确位置上,那么需要遍历的轮数就是 n–1。 完成 n–1 轮后,最小的元素必然在正确位置上,因此不必再做处理。
下面给出了完整的bubble_sort 函数。该函数以一个列表为参数,必要时会交换其中的元素。
def bubble_sort(alist):
for passnum in range(len(alist)-1, 0, -1):
for i in range(passnum):
if alist[i] > alist[i+1]:
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
测试代码:
a_list = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(f"before sorting: {a_list}")
bubble_sort(a_list)
print(f"after sorting: {a_list}")
assert a_list == sorted(a_list)
输出:
before sorting: [54, 26, 93, 17, 77, 31, 44, 55, 20]
after sorting: [17, 20, 26, 31, 44, 54, 55, 77, 93]
性能测试:
from random import randint, seed
seed(13)
lst_to_sort = [randint(100, 999) for _ in range(1000)]
%timeit bubble_sort(lst_to_sort)
结果:
17.6 ms ± 190 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
在分析冒泡排序算法时要注意,不管一开始元素是如何排列的,给含有 n 个元素的列表排序总需要遍历 n–1 轮。下表展示了每一轮的比较次数。总的比较次数是前 n–1 个整数之和。由于 前 n 个整数之和是 因此前 n–1 个整数之和就是 即 。这表明, 该算法的时间复杂度是 。在最好情况下,列表已经是有序的,不需要执行交换操作。在最 坏情况下,每一次比较都将导致一次交换。
| 轮次 | 比较次数 |
|---|---|
| 1 | n-1 |
| 2 | n-2 |
| 3 | n-3 |
| ... | ... |
| n-1 | 1 |
冒泡排序通常被认为是效率最低的排序算法,因为在确定最终的位置前必须交换元素。“多余”的交换操作代价很大。不过,由于冒泡排序要遍历列表中未排序的部分,因此它具有其他排 序算法没有的用途。特别是,如果在一轮遍历中没有发生元素交换,就可以确定列表已经有序。可以修改冒泡排序函数,使其在遇到这种情况时提前终止。对于只需要遍历几次的列表,冒泡排 序可能有优势,因为它能判断出有序列表并终止排序过程。
下面实现了如上所述的修改,这种排序通常被称作短冒泡。
def short_bubble_sort(alist):
exchanges = True
passnum = len(alist)-1
while passnum > 0 and exchanges:
exchanges = False
for i in range(passnum):
if alist[i] > alist[i+1]:
exchanges = True
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
passnum = passnum - 1
测试代码:
a_list = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(f"before sorting: {a_list}")
short_bubble_sort(a_list)
print(f"after sorting: {a_list}")
assert a_list == sorted(a_list)
输出:
before sorting: [54, 26, 93, 17, 77, 31, 44, 55, 20]
after sorting: [17, 20, 26, 31, 44, 54, 55, 77, 93]
性能测试:
from random import randint, seed
seed(13)
lst_to_sort = [randint(100, 999) for _ in range(1000)]
%timeit short_bubble_sort(lst_to_sort)
结果:
37.6 μs ± 581 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
参考文档
《Python数据结构与算法分析(第2版)》:5.3.1 冒泡排序