今天让咱们来继续聊一聊js算法,经过接下来的讲解,咱们能够了解到搜索算法的基本实现以及各类实现方法的性能,进而发现for循环,forEach,While的性能差别,咱们还会了解到如何经过web worker作算法分片,极大的提升算法的性能。html
同时我还会简单介绍一下经典的二分算法,哈希表查找算法,但这些不是本章的重点,以后我会推出相应的文章详细介绍这些高级算法,感兴趣的朋友能够关注个人专栏,或一块儿探讨。前端
对于算法性能,咱们仍是会采用上一章《前端算法系列》如何让前端代码速度提升60倍中的getFnRunTime函数,你们感兴趣的能够查看学习,这里我就不作过多说明。vue
在上一章《前端算法系列》如何让前端代码速度提升60倍咱们模拟了19000条数据,这章中为了让效果更明显,我将伪造170万条数据来测试,不过相信我,对js来讲这不算啥。。。react
基本思路:经过for循环遍历数组,找出要搜索的值在数组中的索引,并将其推动新数组jquery
代码实现以下:webpack
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次稳定后的结果如图:web
基本思和和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循环(先暂且这么说哈,本质也是如此)。vuex
代码以下:typescript
/**
* 普通算法-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依赖IEnumerable。在运行时效率低于for循环。可是在处理不肯定循环次数的循环,或者循环次数须要计算的状况下,使用foreach比较方便。并且foreach的代码通过编译系统的代码优化后,和for循环的循环相似。
二分法搜索更多的应用场景在数组中值惟一而且有序的数组中,这里就不比较它和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';
}
复制代码
在数据量很大的场景下,二分法效率很高,但不稳定,这也是其在大数据查询下的一点小小的劣势。
哈希表查找又叫散列表查找,经过查找关键字不须要比较就能够得到须要记录的存储位置,它是经过在记录的存储位置和它的关键字之间创建一个肯定的对应关系f,使得每一个关键字key对应一个存储位置f(key)
哈希表查找的使用场景:
在这我先给出一个最简版的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线程帮咱们去处理计算结果,最后将结果合并,经过worker的事件机制传给浏览器,效果十分显著。
好啦,这篇文章虽然比较简单,但十分重要,但愿你们对搜索算法有更加直观的认识,也但愿你们有更好的方法,一块儿探讨交流。
接下来会推出更多优秀的算法,敬请期待哦~
最后,欢迎加入前端技术群,一块儿探讨前端的魅力