初窥门径 - 原来递归斐波那契如此慢

初入算法的人都会听过斐波那契数列,看看维基百科的定义:

斐波那契数列(意大利语 Successione di Fibonacci),又译为费波拿契数斐波那契数列费氏数列黄金分割数列
在数学上,费波那契数列是以递归的方法来定义:

用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出。首几个费波那契系数是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……

如果以编程方式来获取第 N 个数的值,我很自然的就想到递归

// in javascript
function fibonacci(n){
    if(n <= 0) return 0;
    if(n == 1) return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}

看着是不是很简洁? 嗯,很标准,边界确定了,也有一步步递进的求解过程,那我们放在浏览器 console 上跑一跑,顺便看看运行时间,为此再来帮助函数

function time(fn, ...args) {
    var start = new Date().valueOf();
    console.log(fn(...args))
    var end = new Date().valueOf();
    console.log('elapsed: ' + (end - start) + 'ms');
}

先来获取 n = 10 的值,看下面的结果正常,1毫秒一开始也怎么在意。


那再来试试 n = 50的... 等了好一会 还没打印出来结果 还以为浏览器卡了!!!


这才到50, 就花去了330秒,5分多钟了喂,真可怕 !?(・_・;? 连三位数都还没到,更别说w级别以上了。

为毛会这么慢??? 我们以 n = 10 来分析下过程


先原谅我这丑不拉几的字迹... 沿着这个树形结构往回推进,发现Fib(8) 执行了2次,Fib(7)执行了3次,Fib(6)执行3次以上,存在着大量重复的计算,复杂度达到指数级别,而且数量级越大重复越严重。这二叉树没有满,我们按满的算那总的计算次数为 T(N) = 1 + 2 + 4 + 8 + ... + 2^10 => 2^n+1 -1 大概时间复杂度是 O( (2^N), 最牛逼的那个N次方。

换个思路

前面的递归是从第n位往回推导的,那我们正向的去一步步得出相应位置的值,就可以省去反向递归带来的大量重复操作了,也就是常说的递推,时间复杂度为 O(N) 代码如下:

// 递推
function fibonacci(n) {
    if (n <= 0) return 0;
    if (n == 1) return 1;

    var first = 0,
        second = 1,
        index = 1,
        fib = 0;

    while (index++ < n) {
        fib = first + second;
        first = second;
        second = fib;
    }
    return fib;
}

试验下, 50 几乎不耗时


慢慢往上加, 可以看到到1w的时候 js的数字已经装不下了, 但是获取第10w位置的也才需要2ms的时间。


补充@林晓池Smile 评论的说法, 以空间换时间,利用数组来存储已经计算过的斐波那契数列中的值

var memo = [];
function fibonacci(n){
    if(n <= 0) return 0;
    if(n == 1) return 1;
    if(!memo[n])
        memo[n] = fibonacci(n-1) + fibonacci(n-2);
    return memo[n];
}

测试看看



可以看到相比一开始的递归,省去了很多重复的计算;但是获取第10w个数的时候堆栈就溢出了,因为即使记忆了但是还存在递归调用, 递推的方案倒是不会
调用堆栈的上限如下:
Three results:
Node.js: 11034
Firefox: 50994
Chrome: 10402

入门例子就可以体会到合理选择算法的威力了,我要继续努力~ 为分布式系统节省机器

网上对斐波那契有其他更优质的算法,但是那种数学公司俺看不懂。。。 以后再回炉重造学习高数吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容