web前端必修课–掌握算法整理

 浆糊之家   2018-07-03 18:52   209 views 热度值

前言

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

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

 

冒泡排序算法介绍

冒泡排序很简单,就是数组中的相邻元素,两两比较,数值或者 Unicode 码小的元素往前排。

浅解前端必须掌握的算法(一):冒泡排序

具体实现指导如下:

  1. 比较相邻两个元素,若前一个比后一个大,则交换位置;
  2. 第一轮结束之后,最后一个元素的值是最大的;
  3. 接着开始第二轮,但是不用再比较最后一个元素了;
  4. 第一轮除外,以后的每一轮都比前一轮少比较一次;

 

简单选择排序 算法介绍

打个比方,喜欢短线炒股的朋友,习惯短时间内不断地买进卖出,通过价差来实现盈利。但是通常如此频繁操作,即使失误不多,也会因为操作的手续费和印花税而获利较少。另外一种长线炒股的朋友,习惯长时间持有,不断地观察和判断,时机一到便果断买进或卖出,交易次数少,收益颇丰。

上一节说的冒泡排序就类似于短线炒股,不断地比较之后进行交换,完成排序。而本节所要讲解的简单选择排序,类似于长线炒股,虽然也在不断地观察比较,但是会在合适的时机进行交换,并且只移动一次就完成相应关键字的排序定位工作。这就是选择排序法的初步思想。

算法图示:浅解前端必须掌握的算法(二):简单选择排序

具体实现指导: 假设数组中元素个数为 n,则需要比较 n-1 轮,在第 i(1<=i<=n) 轮时,需要经过 n-i 1 次比较,选出 Unicode 码最小的元素,并在本轮结束后与第 i 个元素进行交换,当然了,若第 i 个元素本来就是最小的,就不用进行交换了。注:约定第 1 个元素的下标为 0。

 

 

直接插入排序 算法介绍

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

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

算法图示:
浅解前端必须掌握的算法(三):直接插入排序

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

 

希尔排序算法介绍

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。——维基百科

希尔排序是 D.L.Shell 于 1959 年提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是 O(n²),希尔排序算法是突破该事件复杂度的第一批算法之一。

科学家希尔研究出来的这种排序方法,对直接插入排序改进后可以增加效率。

希尔排序算法阐释

上一节我们讲到的「直接插入排序」,它的效率在数组本身就是基本有序以及元素个数较少时,它的效率是很高的。但问题就是,这两个条件本身就很苛刻。如何让程序争取实现这俩条件呢?答案就是将原本有大量元素的数组进行分组,分隔成若干子数组,这样每个子数组的待排序的元素个数就比较少了,然后在子数组内分别进行「直接插入排序」,当整个数组基本有序时,再对全体元素进行一次「直接插入排序」。

所谓基本有序,就是小的元素基本在前面,大的基本在后面,不大不小的基本在中间。要注意像 [2,1,3,6,4,7,5,8,9] 这样的可以称为基本有序,但 [1,5,9,3,7,8,2,4,6] 这样的就谈不上了。

因此我们在分割子数组时,需要采取跳跃分割的策略:将相距某个增量的记录组成一个子数组,这样才能保证在子数组内分别进行直接插入排序后的得到的结果是基本有序,而不是局部有序

浅解前端必须掌握的算法(四):希尔排序

举例说明

这个算法无论怎么解释都会显得含糊不清,直接来个栗子,就拿上图来说明。

假设现在有一数组 arr: [8,9,1,7,2,3,5,4,6,0],我们设定初始化步长为 gap=arr.length/2=10/2,即 5。按照我们上面说的「跳跃分割策略」,按增量为 5 分割子数组,将每列看成是一个子数组:

 

然后对每列进行类直接插入排序,可得:

 

则此时原数组顺序应变成: [3,5,1,6,0,8,9,4,7,2],然后再缩小增量, gap=5/2=2,则数组分割如下:

 

继续对每列进行直接插入排序,可得:

 

则此时元素组顺序应变成: [0,2,1,4,3,5,7,6,9,8],这就是基本有序了。最后一轮再进行微调即可,所以此时增量应计算得为: gap=2/2=1,则直接对数组应用直接插入排序即可,最后得到:

 

 

综上所述,希尔排序算法的出现,我们终于突破了慢速排序的时代,也即超越了时间复杂度为 O(n²)。

 

堆排序--文章结构

先上一张堆排序动画演示图片:

web前端必修课--掌握算法整理

简单的二叉树

要了解堆,必须先了解一下二叉树,两者关系在下一步阐述。

二叉树(Binary Tree)是每一个节点最多有两个分支的树结构,通常分支被称作「左子树」和「右子树」,分支具有左右次序,不能随意颠倒。

二叉树第 i 层最多拥有 2^(i-1) 个节点,深度为 k 的二叉树最多共有 2^(k 1)-1 个节点,且定义根节点所在的层级 i=0,所在的深度 k=0。注意该定义在全文起作用,后续不继续提及。

浅解前端必须掌握的算法(五):堆排序(上)

二叉树示意图

简单的满二叉树

假设某个二叉树深度为 k,第 i 层拥有 2^(i-1) 个节点,且总共拥有 2^(k 1)-1 个节点,这样的二叉树称为「满二叉树」。

换句话说,二叉树的每一层都是满的,除了最后一层上的节点,每一个节点都具有左节点和右节点。

浅解前端必须掌握的算法(五):堆排序(上)

满二叉树示意图

简单的完全二叉树

假设某个二叉树深度为 k,共有 n 个节点,当且仅当其中的每一个节点,都可以和同样深度为 k 的满二叉树上的,按层序编号相同的节点,也就是序号为 1 到 n 的节点,均一一对应时,这样的二叉树称为「完全二叉树」。

满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树。

浅解前端必须掌握的算法(五):堆排序(上)

完全二叉树示意图

如下的就不是完全二叉树,树 1 中 10 号节点缺失,树 2 中 6、7 号节点缺失,树 3 中 10、11 号节点缺失。浅解前端必须掌握的算法(五):堆排序(上)

不是完全二叉树示意图

 发表评论


表情