码迷,mamicode.com
首页 > 其他好文 > 详细

递归函数初探讨

时间:2016-08-13 22:30:52      阅读:316      评论:0      收藏:0      [点我收藏+]

标签:

什么是递归?

所谓的递归 ,就是函数自己直接或者间接的调用自己。复杂算法通常比较容易使用递归实现 从前有座山,山里有座庙,庙里有个老和尚讲故事,从前有座山,山里有座庙,庙里。。。 这个故事就是现实中递归的一个例子,循环往复,生生不息。

 以下就是递归函数最简单的一个例子

function foo(n){
        return n + foo(n-1);
    }
    foo();

递归中最重要的就是如何跳出循环,因为只有程序跳出了才有结果。如果定义错误,或者缺少终结条件 可导致冻结用户界面

递归的思想:划归思想

递归的思想就是划归思想。写一个递归函数调用自己,最终还是要转换为自己的这个函数。

假如有一个函数fn,如果它是递归函数的话,也就是说这个函数体内的问题还是转换为fn的形式。

递归思想就是将一个问题转化为一个已解决的问题来实现

递归函数的求解过程

案例1:求1到100的和

常规求法,通过for循环

var sum =0;
for(var i=1;i<=100;i++){
    sum+=i;
}
console.log(sum);

递归函数方法:

1.首先假定递归函数已经写好,假设是函数fn,也就是说fn(100)就是求1到100的和 2.寻找递推关系,就是n和n-1,或者n-2之间的关系,fn(n)==n+fn(n-1);

 var sum = fn(100);
    sum =fn(99)+100;

3.将递推结构转换为递归体

function fn(n){
        return n+fn(n-1);
    }

4.将临界条件加到递归体中

function fn(n){
        if(n==1) return 1;
        return fn(n-1)+n;
    }

递归的一些小案例

案例2:数列: 1, 1, 2, 4, 7, 11, 16, … 求 第 n 项, 求前 n 项和.

分析过程 1.假设已经得到结果为函数fn,fn(10),就是第10项 2.找递推关系

* 1, 2    =>  fn( 1 ) + 0 = fn( 2 )
* 2, 3  =>  fn( 2 ) + 1 = fn( 3 )
* 3, 4  =>  fn( 3 ) + 2 = fn( 4 )
* ...
* n-1, n  =>  fn( n-1 ) + n - 2 = fn( n )

2.临界条件 n == 1 => 1 3.那么递归体就清楚了,临界条件就是n ==1 =>1

function fn(n){
     if(n==1) return 1;
     return fn(n-1)+n-2;
 }

前n项的和

 function sum(n){
     if(n==1) return 1;
     retrun sum(n-1)+fn(n);
 }

案例3:Fibonacci 数列: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, … 求其第 n 项.

分析过程: 1.假设已经得到结果为函数fib,fib(10),就是第10项 2.找递推关系

2, 3 => fib( 1 ) + fib(2) = fib( 3 )
3, 4 => fib( 2 ) + fib(3) = fib( 4 )
...
9, 10 => fib(8)+fib(9) = fib(10)
n-1, n => fib( n-2 ) + fib(n - 1) = fib( n )

2.临界条件 n == 1||n==2 => 1

function fib(n){
     if(n==1||n==2) return 1;
     return fib(n-2)+fib(n-2);
 }

这里又涉及到另一个问题,递归函数的性能问题。 假如我们用递归的方法求斐波那契数列前n项的和,应该怎么计算?

设置一个变量count

var count=0;
 function fib(n){
     count++;
     if(n==1||n==2) return 1;
     return fib(n-2)+fib(n-2);
 }
// sum(5)时,count为14; 
// sum(10),count为113次
 // sum(20),count为4071次
 // sum(40),count为4194259次

可以看出,随着求和数字的增大,递归函数的计算次数几乎爆炸性增加。 如果n为成千上万的时候,sum(n)成了不可完成的任务。

如果解决递归函数性能低的问题?

* 递归函数求和性能低的原因是重复计算,如果每次将计算的结果存储起来。 * 再每次需要的时候先看有没有存储过该数据,如果有这个数据,直接拿出来使用 * 如果没有再递归,仍旧把计算的结果再次存储起来,以便下次使用。

斐波那契数列求n项代码优化如下:

var data=[1,1];
    function fib2(n){
        //先看看数组中有没有
        var v = data[n];
        if(v===undefined){
        //这里用递归求解
        if(n==1||n==2) return 1;
        v = fib2(n-1)+fib2(n-2);
        data[n]=v;
        }else {
        //数组有就直接返回v
        return v;
        }
    }

通过优化后的代码来计算次数

 var count2 = 0;
        function fib2( n ) {
            count2++;
            var v = data[ n ];
            if ( v === undefined ) {
                v = fib2( n-1 ) + fib2( n-2 );
                data[ n ] = v;
            }
            return v;
        }

求和 sum(n)

* //   sum(5)时,count为12;    `
* //   sum(10),count为27次`
* //   sum(20),count为57次`
* //   sum(40),count为117次`

可以看出通过数据的缓存,能极大的减少计算次数,提高递归函数的性能。

减少工作量就是最好的性能优化技术,代码所做的事情越少,它的运行速度就越快。根据这些原则,避免 重复工作很有意义。而多次执行相同的任务也是浪费时间。通过缓存先前的计算结果为后续的计算所用, 避免了重复工作。

 

递归函数初探讨

标签:

原文地址:http://www.cnblogs.com/newwebdeveloper/p/5768963.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!