普通视图

发现新文章,点击刷新页面。
昨天以前首页

JavaScript算法 - 冒泡排序

作者 梅川_酷子
2026年1月7日 18:03

冒泡排序(从小到大)

生成水面冒泡图片.png

/**
* 文字描述,毕竟不如口语表达,所以,这里有一些帮助阅读的方法
* 释义:
*    项:"数组的 0 项",指的是数组 index 为 0 的值
*
* tips:
* 1. 将会用到的数组,都是复杂度最高的数组,也就是原始排序为 [3,2,1] 这样从大到小的数组,有助于直观理解
* 2. 如果觉得有点乱,就关注函数返回的结果。上一步结果,就是我们下一步的根本
*/
如果数组一共有两项
  const myArr = [9, 8]
  const mySort = (arr) => {
    if (arr[0] > arr[1]) {
      ;[arr[0], arr[1]] = [arr[1], arr[0]]
    }
    return arr
  }
  const result = mySort(myArr)
  console.log(result, 'result') // [ 8, 9 ]

此时数组变为:[ 8, 9 ] 总结:以上是最简单的排序。数组只有两项,0 项和 1 项。比大小、换位,没了

如果有三个呢
  const myArr = [9, 8, 7]
  const mySort = (arr) => {
    if (arr[0] > arr[1]) {
      ;[arr[0], arr[1]] = [arr[1], arr[0]]
    }
    return arr
  }
  const result = mySort(myArr)
  console.log(result, 'result')// [ 8, 9, 7 ]

此时的数组变为:[ 8, 9, 7 ]
看着这个数组,总结:预料之中,0 项和 1 项换位。接下来呢?

排序后数组的含义可以解释为:
可以确定:数组的 1 项,是数组 0 项、1 项中的的最大值
不能确定:数组的 2 项,更大还是更小

!那么,让数组的 1、2 项比大小,就确定了数组中最大的是谁

代码延申
  const myArr = [9, 8, 7]
  const mySort = (arr) => {
    // 第一步
    if (arr[0] > arr[1]) {
      ;[arr[0], arr[1]] = [arr[1], arr[0]]
    }
    // 走到此处,arr 的值为 [ 8, 9, 7 ]

    // 第二步
    if (arr[1] > arr[2]) {
      ;[arr[1], arr[2]] = [arr[2], arr[1]]
    }
    // 走到此处,arr 的值为 [ 8, 7, 9 ]
    return arr
  }
  const result = mySort(myArr)
  console.log(result, 'result') // [ 8, 7, 9 ]

此时的数组变为:[ 8, 7, 9 ]

看着这个数组,总结:延申后,我们确定了最大值,且移动到了最右边
希望这里,你会感受到思路在变清晰

排序后的数组含义可以解释为
可以确定:0 项和 1 项,都比 2 项小。2 项,是数组的最大值
不能确定:数组的 0 项、1 项,谁大

!那么,让数组的 0、1 项比大小。(因为已经确定了 2 项最大,那么,确定了 0、1 的大小关系,就确定了全部的大小关系)

代码再延申
  const mySort = (arr) => {
    // 第一步
    if (arr[0] > arr[1]) {
      ;[arr[0], arr[1]] = [arr[1], arr[0]]
    }
    // 走到此处,arr 的值为 [ 8, 9, 7 ]

    // 第二步
    if (arr[1] > arr[2]) {
      ;[arr[1], arr[2]] = [arr[2], arr[1]]
    }
    // 走到此处,arr 的值为 [ 8, 7, 9 ]

    // 第三步(与 第一步 完全一致)
    if (arr[0] > arr[1]) {
      ;[arr[0], arr[1]] = [arr[1], arr[0]]
    }
    // 走到此处,arr 的值为[ 7, 8, 9 ]
    return arr
  }
  const result = mySort(myArr)
  console.log(result, 'result') // [ 7, 8, 9 ]

此时的数组变为:[ 7, 8, 9 ],是我们要的结果

思路总结:

我们排序的方式为:  
    0、1 对比换位,1、2 对比换位,确定 2  
    0、1 对比换位,确定 0、1  

思路扩展:

尝试想象一下,当数组的数量为四个
    0、1 对比换位,1、2 对比换位,2、3 对比换位,确定 3
然后再重复一下刚刚实现的经过
    0、1 对比换位,1、2 对比换位,确定 2
    0、1 对比换位,确定 0、1
至此,一种算法入门的排序思路已经出现,它被称为:冒泡排序 ~咕嘟咕嘟

根据思路扩展,尝试实现算法:

// 首先,写出第一轮循环对比:得到数组中最大值并移动到最右边
  const arr = [9, 8, 7, 6]
  const bubbleSort = (arr) => {
    // 先把之前的对比的判断,把索引改成动态的
    // if (arr[i] > arr[i + 1]) {
    //   ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
    // }
    
    // 首先想到for循环。能写出来什么样呢
    // for()
    // 我们需要用一些数字。跟循环的次数有关
    // 一般而言,都会拿数组的长度来用。这里,数组的长度有什么用处
    // arr.length // 4
    // for (let i = 0; i < ???; i++) {
    //   if (arr[i] > arr[i + 1]) {
    //       ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
    //     }
    // }
    
    // 关键是,i 要小于几呢?那就先要确定,我们要对比多少次,然后再给出限制
    // 这个对比的次数,要依据 < 思路扩展 > 中的第一轮对比!其中第一轮,经过了 3 次对比换位
    // 又因为我们是从 0 开始的。所以,要拿到的数字是0、1、2,所以要小于3
    // 数组的长度跟这个数字的关系就是 length - 1,这就是我们要小于的值
    for (let i = 0; i < arr.length - 1; i++) {
      if (arr[i] > arr[i + 1]) {
        ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
      }
    }
    return arr
    // 如果从 1 开始,那就另一回事了
  }
  console.log(bubbleSort(arr)) // [ 8, 7, 6, 9 ]

这时候我们已经把最大的移动到了最右边,第一步完成了
然后呢?接下来,我们要对比前三个,不对比第四个了。这个怎么写啊
我们要让这个循环再来一遍。但是,循环次数要少一次。重要!!!
让循环再来一次,也就是说,让这个循环循环

  const bubbleSort = (arr) => {
    // for()
    // 外边这个循环怎么加呢,要让里面的循环,走几轮呢?跟里面的循环有什么关系呢?
    // 再一次,依据 < 思路扩展 > ,要让里面循环 3 轮,就能得到结果了
    // 里面循环对比的次数不断减 1 的,那让外面的循环不断减 1,并让这个数字同步到里面对 i 的限制
    // for(let j = ???; j >= 0; j--){
    //    for (let i = 0; i < arr.length - 1; i++) {
    //      if (arr[i] > arr[i + 1]) {
    //        ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
    //      }
    //    }
    // }
    // 让外面的 j ,设定为里面的 i 的初始值,然后逐渐变小,最终等于 0,然后结束
    for (let j = arr.length - 1; j >= 0; j--) {
      for (let i = 0; i < j; i++) {
        if (arr[i] > arr[i + 1]) {
          ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
        }
      }
    }
    return arr
  }
  console.log(bubbleSort(arr)) // [ 6, 7, 8, 9 ]
主线代码完成
  const bubbleSort = (arr) => {
    for (let j = arr.length - 1; j >= 0; j--) {
      for (let i = 0; i < j; i++) {
        if (arr[i] > arr[i + 1]) {
          ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
        }
      }
    }
    return arr
  }
// 随便输入一些,看看效果
console.log(bubbleSort([543, 4, 76, 524, 24, 65, 23, 235, 3245])) // [ 4, 23, 24, 65, 76, 235, 524, 543, 3245 ]
后续优化:隔离数据源、减少非必要性能开销
  const bubbleSort = (array) => {
    const arr = [...array]
    for (let j = arr.length - 1; j >= 0; j--) {
      let swapped = false
      for (let i = 0; i < j; i++) {
        if (arr[i] > arr[i + 1]) {
          ;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
          swapped = true
        }
      }
      if (!swapped) break
    }
    return arr
  }

完成。

❌
❌