冒泡排序(Bubble Sort)是最经典的比较排序算法之一,其核心思想是通过相邻元素的反复交换,将最大(或最小)的元素逐步”冒泡”到数组的一端。尽管它在实际工程中的使用频率不如快速排序或归并排序,但冒泡排序的教学价值极高:它直观展示了排序的本质——通过比较和交换消除逆序对,同时其优化版本(提前终止标志位)也引入了算法优化的基本思维。
算法原理
冒泡排序的基本流程如下:从数组的第一个元素开始,依次比较相邻的两个元素,如果前一个元素大于后一个元素,则交换它们。每一轮遍历结束后,当前未排序区间的最大元素会”沉”到正确的位置。重复这个过程,直到整个数组有序。
为了优化性能,可以引入一个布尔标志位 swapped。如果在某一轮遍历中没有发生任何交换,说明数组已经有序,此时可以提前终止排序。这个优化在最优情况下将时间复杂度降为 O(n)。
Java 实现
import java.util.Arrays;
/**
* 冒泡排序完整实现,包含基础版本与优化版本
*/
public class BubbleSort {
/**
* 基础冒泡排序:每轮将当前最大值移动到末尾
*
* @param arr 待排序数组
*/
public static void bubbleSort(int[] arr) {
int n = arr.length;
// 外层循环控制排序轮数,每轮确定一个元素的最终位置
for (int i = 0; i < n - 1; i++) {
// 内层循环进行相邻元素比较与交换
// 已经排好序的末尾元素无需再比较,所以范围是 0 到 n-1-i
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换相邻逆序元素
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 优化版冒泡排序:引入提前终止机制
* 当某一轮未发生交换时,说明数组已有序,直接退出
*
* @param arr 待排序数组
*/
public static void bubbleSortOptimized(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
boolean swapped = false;
for (int j = 0; j < n - 1 - i; 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;
}
}
}
/**
* 进一步优化的冒泡排序:记录最后一次交换的位置
* 该位置之后的元素已有序,下一轮只需比较到此位置
*
* @param arr 待排序数组
*/
public static void bubbleSortAdvanced(int[] arr) {
int n = arr.length;
// 记录每轮最后一次发生交换的位置,该位置之后已有序
int sortBorder = n - 1;
while (sortBorder > 0) {
int lastSwapIndex = 0;
for (int j = 0; j < sortBorder; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
lastSwapIndex = j; // 更新最后交换位置
}
}
// 缩小下一轮比较范围
sortBorder = lastSwapIndex;
}
}
public static void main(String[] args) {
int[] arr1 = {64, 34, 25, 12, 22, 11, 90};
int[] arr2 = arr1.clone();
int[] arr3 = arr1.clone();
System.out.println("原始数组: " + Arrays.toString(arr1));
bubbleSort(arr1);
System.out.println("基础排序结果: " + Arrays.toString(arr1));
bubbleSortOptimized(arr2);
System.out.println("优化排序结果: " + Arrays.toString(arr2));
bubbleSortAdvanced(arr3);
System.out.println("进阶优化结果: " + Arrays.toString(arr3));
// 测试已有序数组的最优性能
int[] sorted = {1, 2, 3, 4, 5, 6, 7};
bubbleSortOptimized(sorted);
System.out.println("已有序数组通过优化版处理: " + Arrays.toString(sorted));
}
}
复杂度分析
| 指标 | 基础版本 | 优化版本 |
|---|---|---|
| 最优时间复杂度 | O(n²) | O(n) |
| 平均时间复杂度 | O(n²) | O(n²) |
| 最坏时间复杂度 | O(n²) | O(n²) |
| 空间复杂度 | O(1) | O(1) |
| 稳定性 | 稳定 | 稳定 |
冒泡排序是稳定排序,因为相等元素的相对位置不会在交换过程中改变。空间复杂度为 O(1),属于原地排序算法。
适用场景与总结
冒泡排序适用于数据量极小(n < 100)或数据基本有序的场景。在教学中,它是理解排序算法、逆序对、以及算法优化思维的绝佳入门案例。对于大规模数据,应优先选择快速排序、归并排序或堆排序等更高效的算法。