在 2025 收官前,看清 Data + AI 的真实走向,点击查看 BUILD 大会精华版 了解详情
写点什么

前端进阶: 总结几个常用的 JS 搜索算法和性能对比

  • 2020-12-07
  • 本文字数:2532 字

    阅读完需:约 8 分钟

前端进阶: 总结几个常用的 JS 搜索算法和性能对比

前言


今天让我们来继续聊一聊 JS 算法,通过接下来的讲解,我们可以了解到搜索算法的基本实现以及各种实现方法的性能,进而发现 for 循环,forEach,While 的性能差异,我们还会了解到如何通过 Web Worker 做算法分片,极大的提高算法的性能。


同时我还会简单介绍一下经典的二分算法哈希表查找算法,但这些不是本章的重点,之后我会推出相应的文章详细介绍这些高级算法,感兴趣的朋友可以关注我的专栏,或一起探讨。


对于算法性能,我们还是会采用上一章 《前端算法系列》如何让前端代码速度提高60倍 中的 getFnRunTime 函数,大家感兴趣的可以查看学习,这里我就不做过多说明。


在上一章 《前端算法系列》如何让前端代码速度提高60倍 我们模拟了 19000 条数据,这章中为了让效果更明显,我将伪造 170 万条数据来测试,不过相信我,对 js 来说这不算啥。。。


1. for 循环搜索


基本思路:通过 for 循环遍历数组,找出要搜索的值在数组中的索引,并将其推进新数组


代码实现如下:


const getFnRunTime = require('./getRuntime');
/** * 普通算法-for循环版 * @param {*} arr * 耗时:7-9ms */ function searchBy(arr, value) { let result = []; for(let i = 0, len = arr.length; i < len; i++) { if(arr[i] === value) { result.push(i); } } return result } getFnRunTime(searchBy, 6)
复制代码


测试 n 次稳定后的结果如图:



2. forEach 循环


基本思路和 for 循环类似:


/**  * 普通算法-forEach循环版  * @param {*} arr   * 耗时:21-24ms  */ function searchByForEach(arr, value) {    let result = [];    arr.forEach((item,i) => {        if(item === value) {            result.push(i);        }    })   return result}
复制代码


耗时 21-24 毫秒,可见性能不如 for 循环(先暂且这么说哈,本质也是如此)。


3. while 循环


代码如下:


/**  * 普通算法-while循环版  * @param {*} arr   * 耗时:11ms  */ function searchByWhile(arr, value) {     let i = arr.length,     result = [];    while(i) {        if(arr[i] === value) {            result.push(i);        }        i--;    }       return result}
复制代码


可见 while 和 for 循环性能差不多,都很优秀,但也不是说 forEach 性能就不好,就不使用了。forEach 相对于 for 循环,代码减少了,但是 forEach 依赖 Enumerable。在运行时效率低于 for 循环。但是在处理不确定循环次数的循环,或者循环次数需要计算的情况下,使用 forEach 比较方便。而且 forEach 的代码经过编译系统的代码优化后,和 for 循环的循环类似。


4. 二分法搜索


二分法搜索更多的应用场景在数组中值唯一并且有序的数组中,这里就不比较它和 for/while/forEach 的性能了。


基本思路:从序列的中间位置开始比较,如果当前位置值等于要搜索的值,则查找成功;若要搜索的值小于当前位置值,则在数列的前半段中查找;若要搜索的值大于当前位置值则在数列的后半段中继续查找,直到找到为止


代码如下:


/**   * 二分算法   * @param {*} arr    * @param {*} value    */  function binarySearch(arr, value) {    let min = 0;    let max = arr.length - 1;        while (min <= max) {      const mid = Math.floor((min + max) / 2);        if (arr[mid] === value) {        return mid;      } else if (arr[mid] > value) {        max = mid - 1;      } else {        min = mid + 1;      }    }      return 'Not Found';  }
复制代码


在数据量很大的场景下,二分法效率很高,但不稳定,这也是其在大数据查询下的一点小小的劣势。


5. 哈希表查找


哈希表查找又叫散列表查找,通过查找关键字不需要比较就可以获得需要记录的存储位置,它是通过在记录的存储位置和它的关键字之间建立一个确定的对应关系 f,使得每个关键字 key 对应一个存储位置 f(key)


哈希表查找的使用场景:


  • 哈希表最适合的求解问题是查找与给定值相等的记录

  • 哈希查找不适合同样的关键字对应多条记录的情况

  • 不适合范围查找,比如查找年龄 18~22 岁的同学


在这我先给出一个最简版的 hashTable,方便大家更容易的理解哈希散列:


/** * 散列表 * 以下方法会出现数据覆盖的问题 */function HashTable() {  var table = [];
// 散列函数 var loseloseHashCode = function(key) { var hash = 0; for(var i=0; i<key.length; i++) { hash += key.charCodeAt(i); } return hash % 37 };
// put this.put = function(key, value) { var position = loseloseHashCode(key); table[position] = value; }
// get this.get = function(key) { return table[loseloseHashCode(key)] }
// remove this.remove = function(key) { table[loseloseHashCode(key)] = undefined; }}
复制代码


该方法可能会出现数据冲突的问题,不过也有解决方案,由于这里涉及的知识点比较多,后期我会专门推出一篇文章来介绍:


  • 开放定址法

  • 二次探测法

  • 随机探测法


使用 Web Worker 优化


通过以上的方法,我们已经知道各种算法的性能和应用场景了,我们在使用算法时,还可以通过 Web Worker 来优化,让程序并行处理,比如将一个大块数组拆分成多块,让 Web Worker 线程帮我们去处理计算结果,最后将结果合并,通过 Worker 的事件机制传给浏览器,效果十分显著。


总结


  1. 对于复杂数组查询,for/while 性能高于 forEach 等数组方法

  2. 二分查找法的 O(logn) 是一种十分高效的算法。不过它的缺陷也很明显:必须有序,我们很难保证我们的数组都是有序的。当然可以在构建数组的时候进行排序,可是又落到了第二个瓶颈上:它必须是数组。数组读取效率是 O(1),可是它的插入和删除某个元素的效率却是 O(n)。因而导致构建有序数组的时候会降低效率。

  3. 哈希表查找的基本用法及使用场景。

  4. 条件允许的话,我们可以用 Web Worker 来优化算法,让其在后台并行执行。


好啦,这篇文章虽然比较简单,但十分重要,希望大家对搜索算法有更加直观的认识,也希望大家有更好的方法,一起探讨交流。



作者:徐小夕,未经授权不可转载。

原文链接前端进阶: 总结几个常用的js搜索算法和性能对比

2020-12-07 13:474397

评论

发布
暂无评论
发现更多内容

DNS预热:从可选到必选

柯杰

较 Trino 省 67% 成本,速度快 10 倍,中通快递基于 SelectDB 的湖仓分析架构

SelectDB

数据库 智慧物流 SelectDB OLAP 数据库 湖仓架构

5个步骤轻松上手YashanDB数据库的管理工具

数据库砖家

5个步骤让你快速上手YashanDB数据库

数据库砖家

对长上下文能力有不同要求,怎么选择合适的模型?

Baihai IDP

人工智能 AI LLM 长上下文

大数据-186 Logstash JDBC vs Syslog Input:原理、场景对比与可复用配置(基于 Logstash 7.3.0)

武子康

大数据 elasticsearch 分布式 Logstash ELK

Web3 项目外包开发的管理

北京木奇移动技术有限公司

区块链开发 软件外包公司 web3开发

5个步骤实现YashanDB数据库高可用集群搭建

数据库砖家

5个策略确保YashanDB成功实施与运营

数据库砖家

中国宁波8万㎡试炼场,藏着全球汽车的安全答案

脑极体

AI

DNS劫持防护:从被动监测到主动防御

柯杰

5个步骤助力你的YashanDB数据库迁移成功

数据库砖家

News In Simple:我用 Gemini 重构了英语新闻阅读

Nicooo

英语 gemini #AI编程 News

5个步骤轻松上手YashanDB数据库

数据库砖家

5个步骤实现YashanDB数据库的项目成功交付

数据库砖家

5个策略帮助企业充分利用YashanDB数据库

数据库砖家

GDPS2025 实录:数据库与 AI 双向奔赴

KaiwuDB

数据库 KaiwuDB 分布式多模数据库 KWDB开源数据库

Web3和区块链项目的开发

北京木奇移动技术有限公司

区块链开发 软件外包公司 web3开发

5个步骤助力企业快速上手YashanDB数据库管理

数据库砖家

5个策略提升你对YashanDB数据库的掌控力

数据库砖家

5个常见策略帮助企业顺利实施YashanDB

数据库砖家

2025年远程控制软件排行榜:安全性能哪家强?ToDesk/TeamViewer/向日葵等对比

程序员洲洲

远程控制 向日葵 远控软件 ToDesk TeamViewer

5个步骤快速上手YashanDB数据库管理

数据库砖家

5个策略助你管理YashanDB数据库的事务一致性

数据库砖家

5个常见YashanDB部署误区及其解决方法

数据库砖家

从结果出发,证明钱没白花——详解验证 AI 提效研发的三类指标

思码逸研发效能

AI 研发效能 绩效管理 智能编程 程序员绩效

数字化转型避坑指南:ERP、MES、WMS、QMS如何选?

万界星空科技

wms ERP 生产管理系统 mes QMS

5个策略帮助企业成功实施YashanDB

数据库砖家

5个步骤提升YashanDB数据库整体性能

数据库砖家

5个策略助力提升YashanDB数据库的可用性

数据库砖家

5个常见问题解答:YashanDB的用户体验

数据库砖家

前端进阶: 总结几个常用的 JS 搜索算法和性能对比_大前端_徐小夕_InfoQ精选文章