上面的一篇文章已经简单说明了递归的一些使用,但是留下了一个问题,利用递归求斐波那契的第n项的时候,求到稍微大一点的数的时候,会出现求不出来的现象。
下面对这个现象进行验证
var i = 0;//声明一个变量,用来记录调用getN函数的次数
function getN(n){
i++;
if( n == 1 || n == 2){
return 1;
};
return getN(n-1)+getN(n-2);
}
console.log(getN(30),i);
电脑性能好的小伙伴可以试一下,当尝试求第50项的时候,会发现一直加载求不出来,之所以会出现这个原因是因为调用函数的次数太多了,调用函数是要消耗时间的。调用那么多次是因为求了很多重复的项。下面简单画了一个图,帮助理解一下。
解决方案
不要求那么多重复的项,把已经求过的项,用一个对象保存起来,后面如果还要求这个项就直接去这个对象中取出来。
var obj = {}; //这个obj对象是用来保存已经求过的项的值.
var i = 0; //声明一个变量,用来记录调用getFB这个函数的次数
function getN(n){
i++;
//我们先判断一下这个n位以前求过没有,如果求过就直接取值,如果没有求过就求.
if(obj[n] != undefined){
//如果进到这里来,说明这个n项以前求过已经保存进了obj对象中了.
return obj[n];
}else {
//如果进到这里来,说明这个n项以前没有求过,那就要求咯.
if(n == 1 || n == 2){
obj[n] = 1; //把求出来的数给存起来.
return 1;
}else {
obj[n] = getN(n-1) + getN(n-2);//把求出来的数给存起来.
return obj[n];
}
}
}
console.log(getN(50),i);
//42 267914296 81
//50 12586269025 97
//从i的取值我们可以看出我们已经大大提高了程序的执行效率
按照上面的这种写法,总感觉有些怪怪的,getN是一个独立的函数,但始终要和外面的obj对象取得关联才可以完成它的功能
解决方案使用闭包
function createN(){
var obj = {}; //用来保存已经求过项的值
function getN(n){
if(obj[n] != undefined){
return obj[n];
}else{
if(n == 1 || n == 2){
obj[n]=1;
return obj[n];
}else{
obj[n] = getN(n-1) + getN(n-2);
return obj[n];
}
}
}
return getN;
}
console.log(createN()(50));
以上就是对使用递归求斐波那契第n项的一个程序优化。