冒泡排序算法详解及Python实现

冒泡排序是一种经典的排序算法,通过重复遍历待排序序列,比较相邻元素并交换顺序错误的元素,最终使序列有序。

算法原理

基本思想

冒泡排序的核心思想是重复走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作重复进行,直到没有再需要交换的元素,此时数列已经排序完成。

算法步骤

  1. 比较相邻元素:从第一个元素开始,比较当前元素与下一个元素
  2. 交换错误顺序:如果当前元素大于下一个元素(升序排序),交换它们的位置
  3. 重复遍历:对每一对相邻元素重复上述操作,从开始第一对到结尾最后一对
  4. 缩小范围:每次遍历后,最大的元素会"冒泡"到最终位置,下一次遍历范围减少一个元素
  5. 终止条件:当某次遍历没有发生任何交换时,说明序列已有序,算法结束

时间复杂度分析

情况 时间复杂度 说明
最优情况 O(n) 序列已经有序,只需一次遍历
平均情况 O(n²) 需要多次遍历和比较
最坏情况 O(n²) 序列完全逆序

空间复杂度:O(1),只需要常数级别的额外空间

算法特性

稳定性:冒泡排序是稳定的排序算法,相等元素的相对位置不会改变
适用场景:小规模数据或基本有序的数据集

Python实现

基础版本实现

def bubble_sort_basic(arr):
    """
    基础版冒泡排序
    时间复杂度:O(n²)
    空间复杂度:O(1)
    """
    n = len(arr)
    
    # 外层循环控制遍历次数
    for i in range(n):
        print(f"第{i+1}轮遍历: {arr}")
        
        # 内层循环进行相邻元素比较
        for j in range(0, n - i - 1):
            # 如果前一个元素大于后一个元素,则交换
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                print(f"  交换位置 {j} 和 {j+1}: {arr}")
    
    return arr

# 测试示例
if __name__ == "__main__":
    sample_data = [64, 34, 25, 12, 22, 11, 90]
    print("原始数组:", sample_data)
    sorted_data = bubble_sort_basic(sample_data.copy())
    print("排序结果:", sorted_data)

优化版本实现

def bubble_sort_optimized(arr):
    """
    优化版冒泡排序
    增加提前终止机制,减少不必要的比较
    """
    n = len(arr)
    
    for i in range(n):
        # 标记本次遍历是否发生交换
        swapped = False
        print(f"第{i+1}轮遍历: {arr}")
        
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                # 交换元素
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                swapped = True
                print(f"  交换位置 {j} 和 {j+1}: {arr}")
        
        # 如果本次遍历没有发生交换,说明已经有序,提前结束
        if not swapped:
            print("提前终止:数组已有序")
            break
    
    return arr

# 测试优化版本
if __name__ == "__main__":
    sample_data = [11, 12, 22, 25, 34, 64, 90]  # 已经有序的数组
    print("测试优化版本(已有序数组):")
    sorted_data = bubble_sort_optimized(sample_data.copy())

冒泡排序过程可视化

虽然无法直接生成动态GIF,但可以通过文字描述和分步输出来形象展示冒泡排序的过程:

排序过程示例

以数组 [5, 3, 8, 4, 2] 为例:

第一轮遍历

初始: [5, 3, 8, 4, 2]
比较 5和3: 5>3 → 交换 → [3, 5, 8, 4, 2]
比较 5和8: 5<8 → 不交换 → [3, 5, 8, 4, 2]
比较 8和4: 8>4 → 交换 → [3, 5, 4, 8, 2]
比较 8和2: 8>2 → 交换 → [3, 5, 4, 2, 8]
最大元素8就位

第二轮遍历

当前: [3, 5, 4, 2, 8]
比较 3和5: 3<5 → 不交换 → [3, 5, 4, 2, 8]
比较 5和4: 5>4 → 交换 → [3, 4, 5, 2, 8]
比较 5和2: 5>2 → 交换 → [3, 4, 2, 5, 8]
第二大元素5就位

第三轮遍历

当前: [3, 4, 2, 5, 8]
比较 3和4: 3<4 → 不交换 → [3, 4, 2, 5, 8]
比较 4和2: 4>2 → 交换 → [3, 2, 4, 5, 8]
第三大元素4就位

第四轮遍历

当前: [3, 2, 4, 5, 8]
比较 3和2: 3>2 → 交换 → [2, 3, 4, 5, 8]
全部元素有序,排序完成

完整测试示例

def comprehensive_bubble_sort_demo():
    """
    综合演示冒泡排序的各种情况
    """
    print("=" * 50)
    print("冒泡排序算法综合演示")
    print("=" * 50)
    
    # 测试用例1:普通无序数组
    test_case1 = [64, 34, 25, 12, 22, 11, 90]
    print("
1. 普通无序数组排序:")
    print(f"原始数组: {test_case1}")
    result1 = bubble_sort_optimized(test_case1.copy())
    print(f"排序结果: {result1}")
    
    # 测试用例2:已有序数组(测试优化效果)
    test_case2 = [1, 2, 3, 4, 5, 6]
    print("
2. 已有序数组排序(测试优化):")
    print(f"原始数组: {test_case2}")
    result2 = bubble_sort_optimized(test_case2.copy())
    print(f"排序结果: {result2}")
    
    # 测试用例3:逆序数组
    test_case3 = [6, 5, 4, 3, 2, 1]
    print("
3. 逆序数组排序:")
    print(f"原始数组: {test_case3}")
    result3 = bubble_sort_optimized(test_case3.copy())
    print(f"排序结果: {result3}")

# 运行综合演示
if __name__ == "__main__":
    comprehensive_bubble_sort_demo()

算法优缺点总结

优点

  1. 实现简单:逻辑清晰,易于理解和实现
  2. 稳定性:相等元素的相对位置保持不变
  3. 原地排序:只需要常数级别的额外空间
  4. 适应性:对基本有序的数据效率较高

缺点

  1. 效率低下:时间复杂度为O(n²),不适合大规模数据
  2. 多次交换:需要频繁的元素交换操作
  3. 比较次数多:无论数据状态如何,都需要进行大量比较

实际应用场景

虽然冒泡排序在效率上不如快速排序、归并排序等高级算法,但在以下场景仍有应用价值:

  1. 教学演示:由于其简单性,常用于算法教学
  2. 小规模数据:数据量较小时(n < 50),性能差异不明显
  3. 基本有序数据:当数据已经基本有序时,优化版本效率较高
  4. 嵌入式系统:在资源受限的环境中,简单算法更有优势

冒泡排序作为最基础的排序算法之一,虽然在实际应用中较少使用,但理解其原理对于学习更复杂的排序算法和掌握算法设计思想具有重要意义。通过Python实现,我们可以清晰地观察到算法每一步的执行过程,加深对排序算法的理解。


参考来源

 

更多推荐