【算法基础】冒泡排序算法 - JAVA

一、算法基础

1.1 什么是冒泡排序

冒泡排序是一种简单直观的比较排序算法。它重复地走访待排序的数列,依次比较相邻两个元素,如果顺序错误就交换它们,直到没有元素需要交换为止。

1.2 基本思想

  • 比较相邻元素:从头开始,两两比较相邻元素
  • 交换位置:如果前一个元素大于后一个元素,则交换位置
  • 重复操作:每完成一次迭代,最大的元素会"冒泡"到数组末尾
  • 多次迭代:重复以上步骤,每次排除已排好序的末尾元素

1.3 时间复杂度

  • 最好情况:O(n),当数组已经排好序
  • 最坏情况:O(n²),当数组逆序排列
  • 平均情况:O(n²)

二、冒泡排序的分类

2.1 标准冒泡排序

标准版本每次将最大元素冒泡到末尾:

  • 外层循环:控制排序轮数,最多n-1轮
  • 内层循环:控制每轮比较次数,逐渐减少
  • 无优化:即使数组已排序仍会执行全部循环

2.2 优化冒泡排序

通过标记变量检测一轮比较中是否有交换发生:

  • 设置标记:初始假设本轮无交换
  • 发生交换:更新标记变量
  • 提前终止:若一轮比较无交换发生,则排序完成

三、冒泡排序实现

3.1 标准实现

java 复制代码
public class BubbleSort {
    /**
     * 标准冒泡排序算法
     * @param arr 待排序数组
     */
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        
        // 外层循环控制排序轮数
        for (int i = 0; i < n - 1; i++) {
            
            // 内层循环进行相邻元素比较和交换
            // 每轮结束后,最大的i+1个元素已经排好序
            for (int j = 0; j < n - i - 1; j++) {
                
                // 如果当前元素大于下一个元素,交换它们
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

3.2 优化实现

java 复制代码
public class OptimizedBubbleSort {
    /**
     * 优化版冒泡排序算法
     * @param arr 待排序数组
     */
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        boolean swapped;
        
        // 外层循环控制排序轮数
        for (int i = 0; i < n - 1; i++) {
            swapped = false;
            
            // 内层循环进行相邻元素比较和交换
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换元素
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    
                    // 标记发生了交换
                    swapped = true;
                }
            }
            
            // 如果没有发生交换,说明数组已经有序,提前结束
            if (!swapped) {
                break;
            }
        }
    }
}

3.3 双向冒泡排序(鸡尾酒排序)

java 复制代码
public class CocktailSort {
    /**
     * 双向冒泡排序(鸡尾酒排序)算法
     * @param arr 待排序数组
     */
    public static void cocktailSort(int[] arr) {
        int left = 0;
        int right = arr.length - 1;
        boolean swapped;
        
        while (left < right) {
            swapped = false;
            
            // 从左向右,将最大元素冒泡到右侧
            for (int i = left; i < right; i++) {
                if (arr[i] > arr[i + 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                    swapped = true;
                }
            }
            
            // 如果没有交换,数组已经有序
            if (!swapped) {
                break;
            }
            
            right--; // 最大元素已经到位,缩小右边界
            swapped = false;
            
            // 从右向左,将最小元素冒泡到左侧
            for (int i = right; i > left; i--) {
                if (arr[i] < arr[i - 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i - 1];
                    arr[i - 1] = temp;
                    swapped = true;
                }
            }
            
            // 如果没有交换,数组已经有序
            if (!swapped) {
                break;
            }
            
            left++; // 最小元素已经到位,缩小左边界
        }
    }
}

四、算法分析与优化

4.1 理论推导

冒泡排序的工作原理可以用以下数学表达式描述:

  • 比较次数:(n-1) + (n-2) + ... + 1 = n(n-1)/2
  • 最大交换次数:同上 n(n-1)/2
  • 元素移动次数:最多3×n(n-1)/2(每次交换需要3次移动)

4.2 优化策略

  1. 提前终止优化:如前述,检测是否有交换发生
  2. 记录最后交换位置:每轮记录最后一次交换的位置,下一轮只需扫描到该位置即可
  3. 奇偶交替扫描:类似鸡尾酒排序,减少"乌龟"(小元素靠后)的情况
java 复制代码
public class EnhancedBubbleSort {
    /**
     * 记录最后交换位置的优化冒泡排序
     * @param arr 待排序数组
     */
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        int lastSwappedIndex = n - 1;
        int newLastSwappedIndex;
        
        while (lastSwappedIndex > 0) {
            newLastSwappedIndex = 0;
            
            for (int i = 0; i < lastSwappedIndex; i++) {
                if (arr[i] > arr[i + 1]) {
                    // 交换元素
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                    
                    // 记录最后交换的位置
                    newLastSwappedIndex = i;
                }
            }
            
            // 更新下一轮排序的终止位置
            lastSwappedIndex = newLastSwappedIndex;
        }
    }
}

五、完整示例程序

java 复制代码
public class BubbleSortDemo {
    
    public static void main(String[] args) {
        // 测试数据
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        System.out.println("原始数组: ");
        printArray(arr);
        
        // 执行优化版冒泡排序
        optimizedBubbleSort(arr);
        
        System.out.println("\n排序后数组: ");
        printArray(arr);
    }
    
    /**
     * 优化的冒泡排序实现
     */
    public static void optimizedBubbleSort(int[] arr) {
        int n = arr.length;
        boolean swapped;
        
        for (int i = 0; i < n - 1; i++) {
            swapped = false;
            
            for (int j = 0; j < n - i - 1; j++) {
                // 如果当前元素大于下一个元素,交换它们
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                    swapped = true;
                }
            }
            
            // 如果没有发生交换,数组已经有序
            if (!swapped) {
                System.out.println("提前结束于第 " + (i + 1) + " 轮");
                break;
            }
        }
    }
    
    /**
     * 交换数组中两个元素
     */
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    
    /**
     * 打印数组
     */
    private static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

六、总结

冒泡排序是一种经典的排序算法,其特点如下:

6.1 优点

  • 实现简单:代码直观易懂,适合教学使用
  • 稳定性好:相等元素不会改变相对顺序
  • 原地排序:不需要额外空间
  • 自适应性:对于部分有序数据效率较高

6.2 缺点

  • 效率低下:平均时间复杂度为O(n²)
  • 比较次数多:即使数据已经有序,基本版本仍需大量比较

6.3 适用场景

  • 小规模数据:元素数量较少时表现尚可
  • 教学演示:算法思想简单直观
  • 接近有序数据:优化版本在这种情况下效率较高

冒泡排序虽然在大规模数据中效率不高,但其思想简单,实现容易,是学习排序算法的良好起点。在实际应用中,可根据数据特性选择更高效的排序算法,如快速排序、归并排序等。

相关推荐
Le_ee18 分钟前
数据结构6 · BinaryTree二叉树模板
数据结构·c++·算法
bingbingyihao1 小时前
ES集群搭建及工具类
java·elasticsearch
chirrupy_hamal1 小时前
IntelliJ IDEA
java·intellij idea
weixin_456588151 小时前
【Maven】子POM与父POM
java·maven
EanoJiang1 小时前
算法
不太可爱的叶某人1 小时前
【学习笔记】深入理解Java虚拟机学习笔记——第2章 Java内存区域与内存溢出异常
java·jvm·笔记·学习
昔我往昔2 小时前
使用mybatis实例类和MySQL表的字段不一致怎么办
java·面试·mybatis
月落霜满天2 小时前
贪心算法求解边界最大数
开发语言·算法
懒懒小徐3 小时前
华为OD机试真题 Java 实现【水库蓄水问题】
java·算法·华为od·双指针
阳洞洞3 小时前
滑动窗口leetcode 209和76
算法·leetcode·双指针·滑动窗口