在函数式编程中,经常会利用一些‘缓存’的技巧,也就是常说的记忆功能。这里需要抢到,记忆只是一种编程技巧,本质上是牺牲算法的空间度换区更优的时间复杂度,以提高程序的执行效率。
当一个函数,可能反复计算相同的数据时,为了避免重复地计算,我们可以考虑利用闭包实现函数的‘记忆’功能,以降低时间复杂度。好了,光说不练假把式直接上例子。
求一个数是否是素数的方法 (素数:只能被1和自己整除的数)
function isPrime(num){ if(num<=3){return true} else{ for(var i=2;i<=Math.sqrt(num);i++){ if(num%i==0){return false} } return true; } }
当要判断一个巨大数组中元素是否是素数时候,假设有10万个元素,元素可能有重复的。例如下:
var arr=[]; for(var i=0;i<100000;i++){ arr.push(Math.floor(Math.random()*1000)); }
//调用判断
for(var i=0;i<100000;i++){
isPrime(arr[i]);
}
按照上面的方法执行,有可能会对n多个相同的元素进行相同通的运算,明显这是没有必要的,是否可以把计算的结果保存起来,下一次相同的元素再次计算时候,就可以直接读取结果,不用再计算一次了。为了达成这个想法,我们可以这么做:
var memorize=(function(){ var cache={}; //将值保存在闭包中 return function(num){ if(num<=3){ return true }else if(cache[num]!==undefined){//如果cache中已经记录过,就可以直接返回了 return cache[num]; }else{ for(var i=2;i<=Math.sqrt(num);i++){ if(num%i==0){ return cache[num]=false; } } return cache[num]=true; //将结果存到cache中 } } })();
为了更好说明两种放在在时间复杂度上面的区别,我们可以测试一下:
console.time("方法一"); for(var i=0;i<100000;i++){ isPrime(arr[i]); } console.timeEnd("方法一"); console.time("方法二"); for(var i=0;i<100000;i++){ memorize(arr[i]); } console.timeEnd("方法二");
结果:
可以看到执行效率确实提升了。