| 维度 | 冒泡排序 | 选择排序 |
|---|---|---|
| 基本思想 | 相邻元素两两比较,大者后沉,每轮将最大值“冒泡”至末尾 | 每轮从无序区选出最小值,与无序区首位交换,有序区逐步扩大 |
| 比较次数 | ~N²/2 | ~N²/2 |
| 交换/移动次数 | ~N²/2(最坏) | ~N(最优/最坏均为 N-1 次) |
| 稳定性 | 稳定(相等元素不交换) | 不稳定(交换可能改变相对顺序) |
| 空间复杂度 | O(1) | O(1) |
| 适用场景 | 教学演示、小规模/近乎有序数据 | 交换成本高(如大对象)、需最小化写入操作场景 |
public static void bubbleSort(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 tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
swapped = true;
}
}
if (!swapped) break; // 本轮无交换,已有序
}
}
输入 {5,4,3,2,1} 执行轨迹:
第1轮: 4,3,2,1,5 (5沉底) 第2轮: 3,2,1,4,5 (4沉底) 第3轮: 2,1,3,4,5 (3沉底) 第4轮: 1,2,3,4,5 (2沉底) 第5轮: 无交换,提前结束
public static void selectionSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int minIdx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIdx]) minIdx = j;
}
if (minIdx != i) {
int tmp = arr[i];
arr[i] = arr[minIdx];
arr[minIdx] = tmp;
}
}
}
输入 {5,4,3,2,1} 执行轨迹:
第1轮: 1,4,3,2,5 (选出1,与5交换) 第2轮: 1,2,3,4,5 (选出2,与4交换) 第3轮: 1,2,3,4,5 (选出3,无需交换) 第4轮: 1,2,3,4,5 (选出4,无需交换)
冒泡排序通过相邻交换逐步移动元素,单个元素从头移至尾需 O(N) 次交换(3次赋值)。选择排序每轮仅在确定最终位置后做一次交换,全程仅 N-1 次交换。在 Flash/EEPROM 等写入寿命受限、或大对象移动开销大(需拷贝大量字段)的场景,选择排序优势明显。
Arrays.sort()(双轴快排 + TimSort 混合)或 Collections.sort()。swapped 标志;选择排序可改为堆排序将选择最小值从 O(N) 降为 O(log N),整体复杂度降至 O(N log N)。