js中,什么是冒泡排序

10 阅读5分钟

在 JavaScript 中,冒泡排序(Bubble Sort) 是一种简单但效率较低的排序算法。它的基本思想是重复地遍历要排序的列表,比较相邻的两个元素,如果它们的顺序错误(比如前一个比后一个大,在升序排序中),就交换它们的位置。这个过程会不断重复,直到整个列表有序为止。

之所以叫“冒泡”,是因为较小的元素会像气泡一样逐渐“浮”到列表的顶部(或较大的元素“沉”到底部,取决于实现方式)。

🌟 冒泡排序的基本步骤(以升序为例):

  1. 从第一个元素开始,依次比较相邻的两个元素。
  2. 如果前一个元素大于后一个元素,就交换它们。
  3. 继续这个过程,直到列表末尾。此时,最大的元素已经“冒泡”到了最后。
  4. 对剩下的未排序部分重复上述过程。
  5. 当某一轮遍历中没有发生任何交换,说明列表已经有序,可以提前结束。

✅ 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²),效率较低。不过它是稳定的原地排序算法。在实际项目中我们不会使用它,但在学习算法思想和应对面试时非常重要。我还可以通过设置交换标志来优化它,在数组已基本有序时提前终止。”