文章头图

虽然前端面试中很少会考到算法类的题目,但是你去大厂面试的时候就知道了,对基本算法的掌握对于从事计算机科学技术的我们来说,还是必不可少的,每天花上 10 分钟,了解一下基本算法概念以及前端的实现方式。

另外,掌握了一些基本的算法实现,对于我们日常开发来说,也是如虎添翼,能让我们的 js 业务逻辑更趋高效和流畅。

算法介绍

我们都应该玩过扑克牌了,游戏期间玩家们基本上都是一边摸牌一边理牌,会把牌面值小的牌放到左边,牌面值大的牌放到右边,以升序进行排序(当然也有喜欢降序排序的玩家)。而理牌期间,我们习惯从左往右看牌面值大小,两两比较,将牌抽出,插入到合理的位置。这里我们理牌的方法,就是「直接插入排序法」。

直接插入排序法的基本操作是将一个元素插入到已经排好序的数组中,从而得到一个新的、Unicode 值递增的数组。

算法图示:

直接插入排序算法图示

具体实现指导:

假设数组 arr 中共有 n 个元素,因为比较的话,起码要两个元素,则将要进行 n-1 轮循环。每一轮循环比较下标为 i-1、i(1 <= i <= arr.length-1) 的元素,如果后者元素 Unicode 值更大,则将后者元素先保存到一个变量中,并称该变量为「哨兵变量」。然后进入子循环。从下标为 i-1 的元素开始,每一轮子循环中,都去比较当前元素与「哨兵变量」的 Unicode 值,若当前元素更大,则直接将当前元素的值赋给后一个元素(下标加 1 的元素),然后继续下一轮子循环,直到当前元素不大于「哨兵变量」,则退出子循环,继而进行下一轮的循环。

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var insertSort = function(arr){
var i, j, m, mCnt=0;
var len = arr.length;

for (i=1; i<len; i++) {
if (arr[i] < arr[i-1]) {
// 将更小的那个元素保存起来
m = arr[i];
for (j=i-1; arr[j]>m; j--) {
// 往后挪
arr[j+1] = arr[j];
mCnt++;
}
console.log('移动了 '+mCnt+' 次');
mCnt = 0;
// 直接插入
arr[j+1] = m;
}
}

return arr;
};

insertSort([5,4,3,2,1]);
insertSort([3, 2, 1, 7, 8, 9, 0]);

复杂度分析

当最好的情况,也就是传入的数组本来就是有序的,比如 [1, 2, 3, 4, 5],那么比较次数为 5-1=4 次,由于已经是有序的了,因此没有移动的次数,时间复杂度为 O(n)

当最坏的情况,也就是传入的数组完全是逆序的,比如 [5, 4, 3, 2, 1],那么需要比较如下次:

而移动的次数也将达到如下次数:

综上所述,时间复杂度依旧为 O(n²)