在 JavaScript 中,冒泡排序(Bubble Sort) 是一种简单但效率较低的排序算法。它的基本思想是重复地遍历要排序的列表,比较相邻的两个元素,如果它们的顺序错误(比如前一个比后一个大,在升序排序中),就交换它们的位置。这个过程会不断重复,直到整个列表有序为止。
之所以叫“冒泡”,是因为较小的元素会像气泡一样逐渐“浮”到列表的顶部(或较大的元素“沉”到底部,取决于实现方式)。
🌟 冒泡排序的基本步骤(以升序为例):
- 从第一个元素开始,依次比较相邻的两个元素。
- 如果前一个元素大于后一个元素,就交换它们。
- 继续这个过程,直到列表末尾。此时,最大的元素已经“冒泡”到了最后。
- 对剩下的未排序部分重复上述过程。
- 当某一轮遍历中没有发生任何交换,说明列表已经有序,可以提前结束。
✅ JavaScript 实现示例:
const arr = [64, 34, 25, 12, 22, 11, 90]
function bubbleSort(arr) {
let n = arr.length;
for (let i = 0; i < n - 1; i++) {
let swapped = false; // 优化:记录本轮是否发生交换
for (let 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;
}
}
return arr;
}
console.log(arr)
console.log('冒泡排序 ->', bubbleSort(arr))
⏱️ 时间复杂度:
- 最坏情况(逆序):O(n²)
- 最好情况(已排序):O(n)(加上优化后)
- 平均情况:O(n²)
💾 空间复杂度:
- O(1)(原地排序)
📝 小结:
冒泡排序虽然效率不高,不适合处理大规模数据,但由于其逻辑简单、易于理解,常被用于教学和算法入门。在实际开发中,通常会使用更高效的排序方法(如 Array.prototype.sort(),它在 V8 引擎中使用的是 Timsort 或快排变种)。
面试题解
冒泡排序是前端面试中非常经典的算法题,尤其在考察基础编程能力、逻辑思维和对时间/空间复杂度理解时经常出现。虽然它在实际项目中很少使用(性能较差),但因其原理清晰、代码简洁、易于手写,成为面试高频题。
一、冒泡排序的核心思想
重复遍历数组,比较相邻元素,若顺序错误则交换,直到整个数组有序。
- 每一轮“冒泡”会将当前未排序部分的最大值(升序)或最小值(降序)“浮”到末尾。
- 第 1 轮确定最大值位置,第 2 轮确定次大值……共需
n - 1轮(n 为数组长度)。 - 每轮比较次数递减:第 i 轮比较
n - i次。
二、代码实现(JavaScript)
✅ 基础版(升序)
function bubbleSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) { // 控制轮数(最多 n-1 轮)
for (let j = 0; j < len - 1 - i; j++) { // 每轮比较到未排序部分的末尾
if (arr[j] > arr[j + 1]) {
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
// 或用临时变量:
// let temp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = temp;
}
}
}
return arr;
}
// 测试
console.log(bubbleSort([5, 3, 1, 4, 2])); // [1, 2, 3, 4, 5]
✅ 优化版(提前终止)
如果某一轮没有发生任何交换,说明数组已经有序,可提前结束。
function bubbleSortOptimized(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
let swapped = false; // 标记本轮是否发生交换
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
if (!swapped) break; // 无交换 → 已有序,提前退出
}
return arr;
}
✅ 降序版本
只需将比较条件 > 改为 <:
if (arr[j] < arr[j + 1]) { /* 交换 */ }
三、复杂度分析
| 项目 | 复杂度 |
|---|---|
| 时间复杂度(平均/最坏) | O(n²) |
| 时间复杂度(最好,已有序) | O(n)(优化版) |
| 空间复杂度 | O(1)(原地排序) |
| 稳定性 | ✅ 稳定(相等元素不交换,相对位置不变) |
💡 面试加分点:提到优化方案(提前终止)和稳定性。
四、面试常见问题 & 回答要点
Q1:冒泡排序的时间复杂度为什么是 O(n²)?
A:外层循环 n-1 次,内层平均约 n/2 次,总比较次数 ≈ n(n-1)/2 → O(n²)。
Q2:冒泡排序稳定吗?为什么?
A:稳定。因为只有当前元素 严格大于 后一个元素才交换,相等时不交换,相同元素相对顺序不变。
Q3:如何优化冒泡排序?
A:加入
swapped标志位,若某轮无交换则提前终止,对部分有序数组有显著提升。
Q4:冒泡排序适合什么场景?
A:仅适合小规模数据或教学演示;实际开发中应使用
Array.prototype.sort()(底层通常是快排或归并)。
五、总结(面试话术)
“冒泡排序是一种简单的比较排序算法,通过多次遍历数组,相邻元素两两比较并交换,使较大(或较小)的元素逐步‘冒泡’到末尾。它的实现直观,但时间复杂度为 O(n²),效率较低。不过它是稳定的原地排序算法。在实际项目中我们不会使用它,但在学习算法思想和应对面试时非常重要。我还可以通过设置交换标志来优化它,在数组已基本有序时提前终止。”