解剖前端面试之冒泡排序
冒泡排序没什么实战价值,多用于练习算法,往大了说是逻辑思维,因为它算不上一个好算法。
让我想起了很多往事,学习它就像饭后抽根烟的感觉是一样的,吃饭是重要的,抽烟只是为了爽。
总上所述,文笔会有些放肆,请谨慎观看

好的文章总是要有金句
容易忘记的东西,需要在不同的阶段重新拾起,往往你会得到新的理解,因为总是会剩下一些你忘不掉
这次之所以很兴奋,很放肆,是因为这是第一次被要求手写一下冒泡排序,并且我再一次的忘了,以前在不同的阶段我都有接触过,可能是面试前的准备,也可能是突然想起来看看自己能不能写出来,从看一下文章大致记一下,到尝试理解冒泡两个字。
背景介绍
电话面试后去公司,要求手写,开始的时候我是拒绝的(之前还婉拒了HR说的一小时答的笔试题),面试官提到想看看在这种场景下,10分钟能不能写出来。
我十分流利的写下了下面的解答,三十秒都不到吧,我内心毫无波澜。
正文的味道
我写的冒泡排序
let arr = [1, 2, 34, 2, 19, 10];
for (let i = 0; i < arr.length; i++) {
for (let j = i; j < arr.length; j++) {
if (arr[i] > arr[j]) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
}
console.log(arr);
简单的看一眼,想起冒泡的时间复杂度为
就把let j = i;
改成 j = 0
,虽然不影响结果...
回到家后,在知乎上看了些关于<<士兵突击>>的帖子,突然想在浏览器上运行一下,反正也没几行代码,令我惊奇的是结果竟然对了。
不改还好点,像个选择排序,即便如此仍然差了很多细节
我的记性不好,有些事情告诉自己记住简单的就行了,这是个隐患,没有细节就意味着粗糙
来个粗糙点的冒牌排序
let arr = [1, 2, 34, 2, 19, 10];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
console.log(arr);
我想这个arr.length - 1
不用记在写的时候也能想起来,因为[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
这行代码中是j
和j+1
在交换,
首先二层不处理会报错
其次最后剩一个数也没必要比较,所以一层要处理
更深的一层在于总能把最大的那个带到两边,配上if (arr[j] > arr[j + 1]) {
就是最右边
第一次就把最大的带到最右边,那么下一次最后一个不用参与比较
细节的冒泡排序
let arr = [1, 2, 34, 2, 19, 10];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
console.log(arr);
没检查出这层在于我没有用例子带入,将算法实际的在脑中过一遍,这确实是应该加强的地方,整好了我的效率绝对能再上一层
优化的冒泡排序
优化不能偏离算法的本质
如果二层循环始终没有进入if (arr[j] > arr[j + 1]) {
,说明前面的已经是有序序列
let arr = [1, 2, 34, 2, 19, 10];
for (let i = 0; i < arr.length - 1; i++) {
let isSwap = false;
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
isSwap = true;
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
if (!isSwap) {
break;
}
}
console.log(arr);
下次我忘记的时候能写出这个就很满足了
因为我现在再碰到这种文章已经不会点进去了,自己突然想搞也不可能,只有可能是被面试的时候,被要求手写的概率也很小,且行且珍惜吧!
再细一点的优化
记录发生交换的最后位置,意味着之后的已经不用交换了,适用于后面本就有序数的情况
let arr = [1, 4, 3, 2, 5, 6, 7];
let lastSwapIndex = arr.length;
let pos = 0;
for (let i = 0; i < arr.length - 1; i++) {
let isSwap = false;
for (let j = 0; j < lastSwapIndex; j++) {
if (arr[j] > arr[j + 1]) {
isSwap = true;
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
pos = j;
}
}
if (!isSwap) {
break;
}
// if (arr.length - i - 1 > pos) {
// debugger;
// }
lastSwapIndex = pos;
}
console.log(arr);
let arr = [1, 4, 3, 2, 5, 6, 7];
对比let arr = [1, 2, 34, 2, 19, 10];
这种用例是比较提倡的,查看结果时直观
[1, 4, 3, 2, 5, 6, 7]
第一次 [1, 3, 2, 4, 5, 6, 7]
按照上一个方案,只是7不用比,新方案的话,4不用比了
我是开发者工具弄出来的,更有趣的玩法是,写出代码后,还要举出能起到作用的测试用例并且说出具体流程...,
刺激!还是先写出来吧,我有点怂。
结语
其实还有很多方式能够印象深刻,似乎对于现在的我来说,都不太现实。
我这个人吧,确实不太适合面试,如果能经常锻炼,我肯定是能够进步的,还是提不起兴趣吧。
值得庆幸的是,今天肯定不用担心失眠,明天就能早起去吃油条了,奥利给!
