冒泡排序 bubble sort

1. 冒泡排序过程

  • 假设,我们现在要将这个无序数组[1,5,3,2,6]从小到大来排列

按冒泡排序的思想:

要把相邻的元素两两比较,当一个元素大于右侧相邻元素时,交换它们的位置;当一个元素小于或等于右侧相邻元素时,位置不变

第一轮:

第二轮:

第三轮:

第四轮

轮数 对比次数 确认元素个数 有序区个数
第1轮 4 1 1
第2轮 3 1 2
第3轮 2 1 3
第4轮 1 1 5
结论:
  • 元素交换轮数=数组长度-1
  • 每一轮交换次数=数组长度-当前交换轮

代码实现思路

  • 我们可以用 for 循环嵌套来实现,外部循环控制交换轮数
  • 内部循环用来实现每一轮的交换处理。先进行元素比较,如果元素大于右侧相邻相元素,则两元素位交换,如果不大于,则啥也不做
js 复制代码
// 排序数组
var arr = [1, 5, 3, 2, 6];
// 数组长度
var len = arr.length;
// 外层for控制交换轮数
for (var i = 0; i < len - 1; i++) {
  // 内层for控制每一轮,元素交换次数处理
  for (var j = 0; j < len - i - 1; j++) {
    if (arr[j] > arr[j + 1]) {
      // 交换两元素位置
      var tmp; // 用来交换两个变量的中间变量
      tmp = arr[j];
      arr[j] = arr[j + 1];
      arr[j + 1] = tmp;
    }
  }
}
console.log(arr); // [1, 2, 3, 5, 6]

2. 冒泡排序优化1 --减少没必要的"轮次"

假设法:

  • 如果当前数组以及该是有序,它压根就不会进到交换
  • 假设数组一开始就是有序的,如果从未进入
if 复制代码
     // 交换两元素位置
     var tmp; // 用来交换两个变量的中间变量
     tmp = arr[j];
     arr[j] = arr[j + 1];
     arr[j + 1] = tmp;

代表他是有序的

  • 每一轮循环时假设他是有序的 如果确实没进入交换代表是有序的,后面就不要再交换了

在每一轮开始时,默认打上 isSorted='有序' 标记,如果在这一轮交换中,数据一旦发生交换,就把 isSorted='无序',如果整轮交换中,都没有发生交换,那就表示数组是有序的了。我们就可以退出整个 for 循环的执行。

js 复制代码
// 排序数组
var arr = [1, 5, 3, 2, 6];
// 数组长度
var len = arr.length;
var isSorted;
// 外层for控制交换轮数
for (var i = 0; i < len - 1; i++) {
   isSorted = true; // 假设当前数组是有序的
  // 内层for控制每一轮,元素交换次数处理
  for (var j = 0; j < len - i - 1; j++) {
    if (arr[j] > arr[j + 1]) {
      // 交换两元素位置
      var tmp; // 用来交换两个变量的中间变量
      tmp = arr[j];
      arr[j] = arr[j + 1];
      arr[j + 1] = tmp;
   //如果当前数组以及该是有序,它压根就不会进到交换
       isSorted = false;
    }
  }
  if(isSorted) {
      break;
  }
}
console.log(arr); // [1, 2, 3, 5, 6]

优化的价值

  • 最好情况(原本有序):
    时间复杂度从 O(n²) → O(n)
  • 实际项目中,对"几乎有序"的数据非常友好

3. 冒泡排序优化 2 -- 减少没必要的"比较"

  • 动态缩小"无序区"的右边界
  • 记录每一轮最后一次交换元素的位置,该位置为无序列表的边界,再往右就是有序区了
  • 每一轮比较,比较到上一轮元素最后一次交换的位置(即无序列表的边界)就不再比较了。
变量 解决的问题
isSorted 还要不要继续排序
sortBorder 内层循环跑到哪里为止
index 下一轮新的无序边界
ini 复制代码
// 排序数组
var arr = [98, 2, 3, 45, 4, 1, 5, 78, 6, 7, 8, 20];
// 数组长度
var len = arr.length;
// 当前是否是有序的
var isSorted;
// 有序的边界
var sortBorder = len - 1; //初始值
// 记录每一轮最后一次交换的值,确定下一次循有序边界
var index;

// 外层for控制交换轮数
for (var i = 0; i < len - 1; i++) {
    // 内层for控制每一轮,元素交换次数处理
    isSorted = true; // 有序标记,每轮开始默认为有序,如果一旦发生交换,就会变成flag=false,无序
    for (var j = 0; j < sortBorder; j++) {
        if (arr[j] > arr[j + 1]) {
            // 交换两元素位置
            var tmp; // 用来交换两个变量的中间变量
            tmp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = tmp;
            isSorted = false;
  // 把无序列表的边界,更新为最后一次交换元素的位置
            index = j;
        }
    }
    // 如果无序,记录上一次最后一次交换的元素下标
    if (!isSorted) {
        sortBorder = index;
    }
    // 这一轮多次交换下来,flag没有变为false,说明没有发生元素交换,此时数组已是有序的
    if (isSorted) {
        break; // 退出最外层for循环
    }
}
console.log(arr);
  • 尾部有序的数据越多,收益越大
  • 对"部分有序、局部乱序"的数组特别友好
  • 冒泡排序从"教学算法",进化成了一个还算能用的基础排序
相关推荐
阿蓝灬2 小时前
clientWidth vs offsetWidth
前端·javascript
一代明君Kevin学长2 小时前
快速自定义一个带进度监控的文件资源类
java·前端·后端·python·文件上传·文件服务·文件流
4Forsee3 小时前
【Android】动态操作 Window 的背后机制
android·java·前端
用户90443816324603 小时前
从40亿设备漏洞到AI浏览器:藏在浏览器底层的3个“隐形”原理
前端·javascript·浏览器
小二李3 小时前
第12章 koa框架重构篇 - Koa框架项目重构
java·前端·重构
鸡吃丸子3 小时前
React Native入门详解
开发语言·前端·javascript·react native·react.js
阿蒙Amon3 小时前
JavaScript学习笔记:12.类
javascript·笔记·学习
qq_428723243 小时前
英语歌10个月之前启蒙磨耳朵
前端
Hao_Harrision3 小时前
50天50个小项目 (React19 + Tailwindcss V4) ✨ | DrinkWater(喝水记录组件)
前端·react.js·typescript·vite7·tailwildcss