排序算法-冒泡排序

算法排序-冒泡排序

简介

冒泡排序(Bubble Sort)是最简单直观的排序算法之一。它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端,就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样。

算法原理

冒泡排序的基本思想是:

  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对
  3. 在这一点,最后的元素应该会是最大的数
  4. 针对所有的元素重复以上的步骤,除了最后一个
  5. 重复步骤1~4,直到排序完成

Go语言实现

基础版本

go 复制代码
package main

import "fmt"

// BubbleSort 冒泡排序基础实现
func BubbleSort(arr []int) {
    n := len(arr)
    
    // 外层循环控制排序轮数
    for i := 0; i < n-1; i++ {
        // 内层循环进行相邻元素比较和交换
        for j := 0; j < n-1-i; j++ {
            if arr[j] > arr[j+1] {
                // 交换元素
                arr[j], arr[j+1] = arr[j+1], arr[j]
            }
        }
    }
}

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    fmt.Println("排序前:", arr)
    
    BubbleSort(arr)
    fmt.Println("排序后:", arr)
}

优化版本

go 复制代码
package main

import "fmt"

// BubbleSortOptimized 优化的冒泡排序
func BubbleSortOptimized(arr []int) {
    n := len(arr)
    
    for i := 0; i < n-1; i++ {
        swapped := false // 标记本轮是否发生交换
        
        for j := 0; j < n-1-i; j++ {
            if arr[j] > arr[j+1] {
                arr[j], arr[j+1] = arr[j+1], arr[j]
                swapped = true
            }
        }
        
        // 如果本轮没有发生交换,说明数组已经有序
        if !swapped {
            break
        }
    }
}

// BubbleSortWithSteps 带步骤显示的冒泡排序
func BubbleSortWithSteps(arr []int) {
    n := len(arr)
    fmt.Printf("初始数组: %v\n", arr)
    
    for i := 0; i < n-1; i++ {
        swapped := false
        fmt.Printf("\n第 %d 轮排序:\n", i+1)
        
        for j := 0; j < n-1-i; j++ {
            if arr[j] > arr[j+1] {
                fmt.Printf("  交换 %d 和 %d\n", arr[j], arr[j+1])
                arr[j], arr[j+1] = arr[j+1], arr[j]
                swapped = true
            }
        }
        
        fmt.Printf("  本轮结果: %v\n", arr)
        
        if !swapped {
            fmt.Println("  数组已有序,提前结束")
            break
        }
    }
}

func main() {
    // 测试基础版本
    arr1 := []int{64, 34, 25, 12, 22, 11, 90}
    fmt.Println("=== 基础冒泡排序 ===")
    fmt.Println("排序前:", arr1)
    BubbleSort(arr1)
    fmt.Println("排序后:", arr1)
    
    // 测试优化版本
    arr2 := []int{5, 2, 8, 1, 9}
    fmt.Println("\n=== 优化冒泡排序 ===")
    fmt.Println("排序前:", arr2)
    BubbleSortOptimized(arr2)
    fmt.Println("排序后:", arr2)
    
    // 测试带步骤显示的版本
    arr3 := []int{5, 2, 8, 1}
    fmt.Println("\n=== 带步骤显示的冒泡排序 ===")
    BubbleSortWithSteps(arr3)
}

复杂度分析

时间复杂度

  • 最坏情况: O(n²) - 数组完全逆序时
  • 最好情况: O(n) - 数组已经有序时(优化版本)
  • 平均情况: O(n²)

空间复杂度

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

算法特点

优点

  1. 实现简单: 代码逻辑清晰,容易理解和实现
  2. 原地排序: 只需要常数级别的额外空间
  3. 稳定排序: 相等元素的相对位置不会改变
  4. 自适应性: 对于已经部分有序的数组,优化版本可以提前结束

缺点

  1. 效率低下: 时间复杂度为O(n²),不适合大数据集
  2. 比较次数多: 即使数组已经有序,基础版本仍会进行所有比较

实际应用场景

冒泡排序虽然效率不高,但在以下场景中仍有其价值:

  1. 教学演示: 作为排序算法的入门教学
  2. 小数据集: 当数据量很小时(通常小于50个元素)
  3. 几乎有序的数据: 优化版本对于几乎有序的数据表现较好
  4. 嵌入式系统: 在内存极其有限的环境中,简单性比效率更重要

性能测试

go 复制代码
package main

import (
    "fmt"
    "math/rand"
    "time"
)

// 生成随机数组
func generateRandomArray(size int) []int {
    rand.Seed(time.Now().UnixNano())
    arr := make([]int, size)
    for i := 0; i < size; i++ {
        arr[i] = rand.Intn(1000)
    }
    return arr
}

// 性能测试
func benchmarkBubbleSort(size int) {
    arr := generateRandomArray(size)
    
    start := time.Now()
    BubbleSortOptimized(arr)
    duration := time.Since(start)
    
    fmt.Printf("数组大小: %d, 排序时间: %v\n", size, duration)
}

func main() {
    fmt.Println("=== 冒泡排序性能测试 ===")
    sizes := []int{100, 500, 1000, 2000}
    
    for _, size := range sizes {
        benchmarkBubbleSort(size)
    }
}

总结

冒泡排序是一个经典的排序算法,虽然效率不高,但其简单性使其成为学习排序算法的绝佳起点。通过理解冒泡排序的原理和实现,可以为学习更复杂的排序算法打下坚实的基础。

在实际开发中,除非是处理非常小的数据集或者在资源极其有限的环境中,否则建议使用更高效的排序算法如快速排序、归并排序或者直接使用语言内置的排序函数。

关键要点:

  • 冒泡排序通过重复比较相邻元素并交换来实现排序
  • 时间复杂度为O(n²),空间复杂度为O(1)
  • 是稳定的排序算法
  • 适合教学和小数据集排序
  • 优化版本可以在数组已有序时提前结束
相关推荐
丶小鱼丶几秒前
二叉树算法之【Z字型层序遍历】
java·算法
武文斌7736 分钟前
嵌入式——数据结构:基础知识和链表①
数据结构
岁忧2 小时前
(nice!!!)(LeetCode 每日一题) 2561. 重排水果 (哈希表 + 贪心)
java·c++·算法·leetcode·go·散列表
先做个垃圾出来………2 小时前
1. 两数之和
算法·leetcode·职场和发展
C++ 老炮儿的技术栈2 小时前
在vscode 如何运行a.nut 程序(Squirrel语言)
c语言·开发语言·c++·ide·vscode·算法·编辑器
HKUST_ZJH3 小时前
交互 Codeforces Round 1040 Interactive RBS
c++·算法·交互
九章数学体系3 小时前
九章数学体系:打破“吃苦悖论”,重构学习真谛
数据结构·学习·算法·数学建模·拓扑学
一川月白7093 小时前
数据结构---概念、数据与数据之间的关系(逻辑结构、物理结构)、基本功能、数据结构内容、单向链表(该奶奶、对象、应用)
c语言·数据结构·算法·哈希算法·单向链表·数据关系
展信佳_daydayup3 小时前
8-1 图像增广
算法