代码改变世界

javascript记忆特性

2009-11-03 00:30  BlueDream  阅读(601)  评论(0编辑  收藏  举报

函数可以通过对象来存储先前操作的结果,从而减少无谓的运算,这种优化被称为记忆.

比如说:用JS来递归实现斐波那契数列.Fibonacci一个运算数是前两个运算数的和.最前面的两个数字是0和1.

最容易想到的递归方式就是:

    var fibonacci = function(n){
        
return n < 2 ? n : fibonacci(n - 1+ fibonacci(n - 2);
    }

这里可以看到 比如计算10的斐波那契数.要把9以前每次斐波那契都重新算一遍.显然损失了很多效率.这里我们就可以用

一个数组把每次计算的值给"记忆"起来.以便下次调用可以直接取出.

还有阶乘函数的递归实现:

    var factorial = function(n){
        
return n == 1 ? n : n * arguments.callee(n - 1);
    }

最后为了我们提供了一个记忆模板.可以自己定制规则去实现记忆功能而优化不必要的计算.

记忆模板:

    var memoizer = function(memo/*记忆数组*/, func/*自定义递归函数*/){
        
// 提供一个闭包方法
        var shell = function(n/*递归次数*/){
            
var r = memo[n];
            
if(typeof r !== 'number'){ // 如果存储中没有
                r = func(shell, n);    // 递归调用自定义函数
                memo[n] = r;           // 将没有存储的值存储进去
            }
            
return r;
        };    
        
return shell;
    };

最后给出测试代码,以及使用形式:

<script type="text/javascript">
<!--
    
var memoizer = function(memo/*记忆数组*/, func/*自定义递归函数*/){
        
// 提供一个闭包方法
        var shell = function(n/*递归次数*/){
            
var r = memo[n];
            
if(typeof r !== 'number'){ // 如果存储中没有
                r = func(shell, n);    // 递归调用自定义函数
                memo[n] = r;           // 将没有存储的值存储进去
            }
            
return r;
        };    
        
return shell;
    };
    
// 原形式
    var fibonacci = function(n){
        
return n < 2 ? n : fibonacci(n - 1+ fibonacci(n - 2);
    }
    
// 记忆形式
    var fibonacci2 = memoizer([01]/*初始化记忆仓库*//*提供自定义递归公式*/function(shell, n){
        
return shell(n - 1+ shell(n - 2);
    });

    
// ===========================
    //
    //        fibonacci形式比较
    //
    // ===========================
    for(var i = 0; i < 10; i++){
        document.write(fibonacci(i) 
+ ' ');
    }
    document.write(
'==');
    
for(var j = 0; j < 10; j++){
        document.write(fibonacci2(j) 
+ ' ');
    }

    
// 原形式
    var factorial = function(n){
        
return n == 1 ? n : n * arguments.callee(n - 1);
    }
    
// 记忆形式
    var factorial2 = memoizer([11]/*初始化记忆仓库*//*提供自定义递归公式*/function(shell, n){
        
return n * shell(n - 1);
    });

    
// ===========================
    //
    //        factorial形式比较
    //
    // ===========================
    document.write('<br/>');
    document.write(factorial(
5+ ' == ');
    document.write(factorial2(
5));

//-->
</script>

结果是正确的,但效率高了许多.

0 1 1 2 3 5 8 13 21 34 ==0 1 1 2 3 5 8 13 21 34 
120 == 120