前置知识
学会冒泡排序首先需要学会=> 数组的基本用法 丶for循环丶两个变量交换值
假设你已经会这几个知识点
for (let i = 0; i < 10; i++) {
console.log(i)
}
let a = 1
let b = 2
let temp = a
a = b
b = temp
console.log(a, b) //2 1
第一步,首先看一个示例
定义一个数组,结合前面两个知识点
用一个for循环,从第一个数开始,前一个数和后一个比较, 小的话不变,大的话交换值.
最终让其中一个最大的数到最右边
let arr = [2, 6, 5, 1, 3]
for (let i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
document.write(arr)
//此时打印出来的结果是 2,5,1,3,6 最大的6到了最后面
↓解析循环过程↓
- 第一个for循环: i = 0, arr[i] = 2 , arr[i + 1] = 6, 2比6小, 不变
- 第二个for循环: i = 1, arr[i] = 6 , arr[i + 1] = 5, 6比5大, 6和5交换位置. 此时的数组为 [2, 5, 6, 1, 3]
- 第三个for循环: i = 2, arr[i] = 6 , arr[i + 1] = 1, 6比1大, 6和1交换位置. 此时的数组为 [2, 5, 1, 6, 3]
- 第四个for循环: i = 3, arr[i] = 6 , arr[i + 1] = 1, 6比1大, 6和1交换位置. 此时的数组为 [2, 5, 1, 3, 6]
- 第五个for循环: i = 4, arr[i] = 6 , arr[i + 1] = undefined, 没有必要的对比
以上分析可得知, 循环的次数比数组长度少一次,数组长度5,只需要循环4次
i < arr.length 可以优化成 i < arr.length - 1
另外既然一次循环能让一个较大的数往右移,那么多次循环是不是就可以达到效果呢
于是我猜测只要4轮就能移动完毕, 于是复制了4份一样的循环查看效果
第二步,根据分析循环四遍
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
document.write(arr) //1,2,3,5,6
结果果然是我想要的 1,2,3,5,6
当我们遇到重复执行多遍的代码时应该怎么办呢? 那必然是循环啦
于是我在外面又套个外层循环,循环4次, 4次怎么来的呢? 刚好又是数组长度减一,代码如下↓
for (let j = 0; j < arr.length - 1; j++) {
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
}
// 此时打印出来的结果还是 1,2,3,5,6
document.write(arr)
第三步,优化性能
到这里看似已经OK,但仔细想想发现一个问题
内层循环每次都会从第一个数开始,两两对比,直到最后一个数
但除了第一轮以外,实际上后面每一轮需要对比的次数可以减1
比如只执行一次外层循环,就让最大的数值到达最后一个位置
接着第二个外层循环已经不需要再对最后一个数值进行对比, 因为它肯定是最大了
由此可知内层循环的循环次数是依次递减的
第一次对比4轮
第二次对比3轮
第三次对比2轮
第四次对比1轮
用i < arr.length - 1 就不适合了, 会造成严重的性能浪费
如何递减呢? 有个办法 改成 i < arr.length - j - 1
因为j是从0递增的,数组长度固定 减去j后会让循环判断条件越来越小,由此达到递减的效果
第一次对比4轮 5 - 0 - 1
第二次对比3轮 5 - 1 - 1
第三次对比2轮 5 - 2 - 1
第四次对比1轮 5 - 3 - 1
完美解决! 最终代码如下
for (let j = 0; j < arr.length - 1; j++) {
for (let i = 0; i < arr.length - j - 1; i++) {
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
}
// 此时打印出来的结果还是 1,2,3,5,6 并且性能没有浪费
document.write(arr)