一、简介
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 是否稳定:是
- 优点:空间复杂度较低,稳定, 简单
- 缺点:时间复杂度太高,效率低
二、核心思想
- 外层循环每次找到一个最值(最大或者最小)
- 内层循环进行相邻元素比较
三、排序过程动图
黄色:每轮找到的最大值
绿色:对比的相邻元素
四、代码实现
通用函数
// 位置交换
const change = function (arr, index1, index2){
[arr[index1], arr[index2]] = [arr[index2], arr[index1]];
}
版本一:普通版
普通版本其实没什么好说的,就是每轮通过 相邻元素 间的比较找到一个 最值。
const bubbleSort1 = function (arr) {
let length = arr.length;
// 此循环每次找到一个最值
for (let i = 0; i < length - 1; i++) {
// 此循环进行每轮的相邻元素比较
for (let j = 0; j < length - 1 - i; j++) {
if(arr[j] > arr[j+1]) {
change(arr, j, j+1)
}
}
}
return arr;
}
版本二:检查版
这个版本其实是版本一的优化版。如果已经排好序了,是否还需要进行比较。那么问题来了,如何判定排序完成?其实很简单。当一轮相邻比较中都没有位置交换,说明已经完成排序。
const bubbleSort2 = function (arr) {
let length = arr.length;
// 此循环每次找到一个最值
for (let i = 0; i < length - 1; i++) {
// 本轮比较是否进行了位置交换
let isChange = false;
// 此循环进行每轮的相邻元素比较
for (let j = 0; j < length - 1 - i; j++) {
if(arr[j] > arr[j+1]) {
change(arr, j, j+1)
// 进入了这个if语句,说明进行了位置交换
isChange = true;
}
}
// 本轮没有进行位置交换,说明排序完成
if(!isChange) {
return arr;
}
}
return arr;
}
版本三: 双向冒泡排序(相比于前两种,数据量越大排序越快)
此版本与另外两个版本的思想不同之处在于,它是每轮确定两个最值,一个最大值,一个最小值
const bubbleSort3 = function (arr) {
let small = 0;
let large = arr.length;
while(small < large) {
// 该轮是否发生位置交换
let isChange = false;
// 找大值
for(let i = small; i < large - 1; i++) {
if(arr[i] > arr[i+1]) {
change(arr, i, i+1);
isChange = true;
}
}
large--;
// 找小值
for(let j = large - 1; j > small; j--) {
if(arr[j] < arr[j-1]) {
change(arr, j, j-1);
isChange = true;
}
}
small++;
// 未发生位置交换
if(!isChange) {
return arr;
}
}
return arr;
}