冒泡排序是最古老的排序算法之一,其思想可以追溯到 20 世纪 50 年代计算机科学的早期。1956 年,计算机科学家兼海军军官 Harry H. Goode 在一篇论文中描述了类似冒泡排序的算法。由于其简单直观的特性,冒泡排序成为几乎所有编程入门教材中首先介绍的排序算法。它得名于排序过程中较大的元素会像气泡一样逐渐"浮"到数组的顶端。
冒泡排序的基本思想是:重复地遍历要排序的数组,依次比较相邻的两个元素,如果它们的顺序错误(前一个大于后一个)就交换它们的位置。每一轮遍历都会将当前未排序部分的最大元素"冒泡"到正确的位置。经过 n-1 轮遍历后,整个数组就有序了。
public class BubbleSort {
/**
* 冒泡排序(基础版本)
* @param arr 待排序的整数数组
*/
public static void sort(int[] arr) {
int n = arr.length;
for (int i = 0; i < 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 sortOptimized(int[] arr) {
int n = arr.length;
boolean swapped;
for (int i = 0; i < n - 1; i++) {
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;
}
}
}
/**
* 冒泡排序(泛型版本)
* 支持任何实现了 Comparable 接口的类型
*/
public static <T extends Comparable<T>> void sortGeneric(T[] arr) {
int n = arr.length;
boolean swapped;
for (int i = 0; i < n - 1; i++) {
swapped = false;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j].compareTo(arr[j + 1]) > 0) {
T temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) {
break;
}
}
}
}
| 指标 | 最好情况 | 最坏情况 | 平均情况 |
|---|---|---|---|
| 时间复杂度 | O(n)(优化版) | O(n²) | O(n²) |
| 空间复杂度 | O(1) | O(1) | O(1) |
| 比较次数 | n-1 | n(n-1)/2 | n(n-1)/4 |
| 交换次数 | 0 | n(n-1)/2 | n(n-1)/4 |
冒泡排序是稳定的排序算法,也是原地排序算法。它的优点是实现极其简单,且优化版能够检测到已经有序的数组并提前终止。缺点是效率太低,对于大规模数据完全不可用。