尾遞歸優(yōu)化小記

前言

一般地,對(duì)于java語(yǔ)言而言,普通的遞歸調(diào)用是在java虛擬機(jī)棧上完成的.加入a()是一個(gè)遞歸方法,那么在其內(nèi)部再調(diào)用自己的時(shí)候,假設(shè)為a1(),那么a1()這個(gè)方法變量表將創(chuàng)建在a()方法棧幀之上,從而形成了一個(gè)新的棧幀.因此容易發(fā)現(xiàn),在遞歸思想中,遞歸簡(jiǎn)化了問(wèn)題的表達(dá),但犧牲了虛擬機(jī)棧中的內(nèi)存空間.

普通遞歸

斐波那契遞歸法

public static int fib(int num){
        if(num<2)
            return num;
        else
            return fib(num-2)+fib(num-1);
    }
  • 對(duì)于上面的解法,很容易就會(huì)發(fā)現(xiàn),不但屬于普通遞歸,而且在計(jì)算fib(num-1)是重復(fù)了fib(num-2)的計(jì)算量,因此代碼效率大打折扣.因此效率較高的寫(xiě)法可以用for循環(huán)計(jì)算,
public static int fib3(int n) {
        if (n < 2)
            return n;
        else {
            int pre = 0;
            int suf = 1;
            for (int i = 2; i <= n; i++) {
                int temp = suf;
                suf += pre;
                pre = temp;
            }
            return suf;
        }
    }

斐波那契尾遞歸優(yōu)化

public class Main {
    public static void main(String[] args) {
        
        System.out.print(fib2(3, 0, 1));
    }


    public static int fib2(int count, int pre, int result) {
        if (count == 1)
            return result;
        else
            return fib2(--count, result, result + pre);
    }
}

性能對(duì)比

 public static void main(String[] args) {
        long time = new Date().getTime();

        int num=40;
        System.out.println(fib(num));
        System.out.println("普通遞歸調(diào)用用時(shí):" + (new Date().getTime() - time) + "毫秒");

        time = new Date().getTime();
        System.out.println(fib2(num, 0, 1));
        System.out.println("尾遞歸優(yōu)化調(diào)用用時(shí):" + (new Date().getTime() - time) + "毫秒");

        time = new Date().getTime();
        System.out.println(fib3(num));
        System.out.println("for循環(huán)法調(diào)用用時(shí):" + (new Date().getTime() - time) + "毫秒");
    }
    //輸出
    /*
    102334155
    普通遞歸調(diào)用用時(shí):674毫秒
    102334155
    尾遞歸優(yōu)化調(diào)用用時(shí):0毫秒
    102334155
    for循環(huán)法調(diào)用用時(shí):0毫秒
    */
  • 可以看出有明顯差異,即使普通遞歸法計(jì)算量多了一半,時(shí)間除以2也是387毫秒,這也遠(yuǎn)遠(yuǎn)高于for循環(huán)和遞歸尾優(yōu)化法.

尾遞歸優(yōu)化思想

  • 即遞歸方法return 直接返回方法,注意是直接返回方法,不能是方法加1個(gè)值等形式.這樣在遞歸調(diào)用時(shí),新方法會(huì)覆蓋當(dāng)前棧幀,達(dá)到節(jié)省椪虿荩空間的目的.因此也就不會(huì)有遞歸調(diào)用產(chǎn)生的棧溢出問(wèn)題.

尾遞歸寫(xiě)法

斐波那契例:
//count作為計(jì)數(shù),表示遞歸層次,
//pre代表前一個(gè)值
//result 表示當(dāng)前值
 public static int fib2(int count, int pre, int result) {
        //層次減到1時(shí)返回計(jì)算結(jié)果
        if (count == 1)
            return result;
        else{
        //遞歸調(diào)用時(shí),層次減1,前一項(xiàng)更新為當(dāng)前項(xiàng),所以填result,第三個(gè)參數(shù)即實(shí)現(xiàn)了倒數(shù)第二個(gè)參數(shù)加倒數(shù)第一個(gè)參數(shù).
        return fib2(--count, result, result + pre);
        }
    }
  • 總體而言參數(shù)的書(shū)寫(xiě)分為兩部分
  • 前部分為計(jì)數(shù),后部分為計(jì)算,例如計(jì)算階乘時(shí)候只需要兩個(gè)參數(shù),第一個(gè)計(jì)數(shù),第二個(gè)存結(jié)果.
  • 尾遞歸將全部信息放入了參數(shù)里,因此也就巧妙地避免了需要上一棧幀保存信息.
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扮惦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锯梁,更是在濱河造成了極大的恐慌,老刑警劉巖酵紫,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡鼠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡稳强,警方通過(guò)查閱死者的電腦和手機(jī)场仲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)和悦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人渠缕,你說(shuō)我怎么就攤上這事鸽素。” “怎么了亦鳞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵馍忽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蚜迅,道長(zhǎng)舵匾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任谁不,我火速辦了婚禮坐梯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刹帕。我一直安慰自己吵血,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布偷溺。 她就那樣靜靜地躺著蹋辅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挫掏。 梳的紋絲不亂的頭發(fā)上侦另,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音尉共,去河邊找鬼褒傅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛袄友,可吹牛的內(nèi)容都是我干的殿托。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼剧蚣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼支竹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鸠按,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤礼搁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后目尖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體叹坦,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年卑雁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了募书。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绪囱。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖莹捡,靈堂內(nèi)的尸體忽然破棺而出鬼吵,到底是詐尸還是另有隱情,我是刑警寧澤篮赢,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布齿椅,位于F島的核電站,受9級(jí)特大地震影響启泣,放射性物質(zhì)發(fā)生泄漏涣脚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一寥茫、第九天 我趴在偏房一處隱蔽的房頂上張望遣蚀。 院中可真熱鬧,春花似錦纱耻、人聲如沸芭梯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)玖喘。三九已至,卻和暖如春蘑志,著一層夾襖步出監(jiān)牢的瞬間累奈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工急但, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留澎媒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓羊始,卻偏偏與公主長(zhǎng)得像旱幼,于是被迫代替她去往敵國(guó)和親查描。 傳聞我的和親對(duì)象是個(gè)殘疾皇子突委,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 每逢周末的晚上,都會(huì)很難熬冬三,有深深的罪惡感匀油,一周眨眼過(guò)去,回頭看卻沒(méi)什么進(jìn)步勾笆,想做的事還躺在計(jì)劃表里敌蚜,困擾我的問(wèn)題...
    少俠_知行在路上閱讀 1,413評(píng)論 3 11
  • 2018.10.18
    沐小錦閱讀 225評(píng)論 0 0
  • (此文為高二時(shí)期某一天寫(xiě)的,今天翻日記本無(wú)意看到窝爪,有些詞句讓現(xiàn)在的自己感到驚艷弛车,特此分享齐媒,莫見(jiàn)笑。) 所有...
    黎同學(xué)閱讀 256評(píng)論 0 1