日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅谈尾递归

發(fā)布時(shí)間:2023/12/19 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈尾递归 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

淺談尾遞歸

2013-02-10 14:12:57

在《數(shù)據(jù)結(jié)構(gòu)與算法分析:C描述》(Data Structures and Algorithm Analysis In C)的第三章中,以打印鏈表為例,提到了尾遞歸(tail recursion)并指出了尾遞歸是使用遞歸極其不當(dāng)?shù)睦?#xff0c;它指出雖然編譯器會(huì)對尾遞歸自動(dòng)優(yōu)化,但即便如此最好還是不要去寫尾遞歸。而我在《算法精解:C語言描述》(Mastering Algorithms with C)中也看到書中提到編譯器會(huì)對尾遞歸進(jìn)行優(yōu)化,但是此書貌似看起來很提倡使用。
這里對于不了解尾遞歸為何物的童鞋們,我想探討幾個(gè)基本問題。
【1】什么是尾遞歸?
【2】編譯器是怎樣優(yōu)化尾遞歸的?
【3】優(yōu)化工作交給編譯器還是交給自己?
第一個(gè)問題,什么是尾遞歸?
直接上代碼:

遞歸與尾遞歸

這兩個(gè)函數(shù)都是在計(jì)算n的階乘,結(jié)果一樣的,但只有下面的facttail函數(shù)才是尾遞歸。
所以可以看出,尾遞歸的概念就是函數(shù)返回之前的最后一個(gè)操作若是遞歸調(diào)用,則該函數(shù)進(jìn)行了尾遞歸,而上面的fact函數(shù),最后一個(gè)操作是乘法,所以顯然不是尾遞歸。
第二個(gè)問題,編譯器是怎樣優(yōu)化尾遞歸的?
我們知道遞歸調(diào)用是通過棧來實(shí)現(xiàn)的,每調(diào)用一次函數(shù),系統(tǒng)都將函數(shù)當(dāng)前的變量、返回地址等信息保存為一個(gè)棧幀壓入到棧中,那么一旦要處理的運(yùn)算很大或者數(shù)據(jù)很多,有可能會(huì)導(dǎo)致很多函數(shù)調(diào)用或者很大的棧幀,這樣不斷的壓棧,很容易導(dǎo)致棧的溢出。
我們回過頭看一下尾遞歸的特性,函數(shù)在遞歸調(diào)用之前已經(jīng)把所有的計(jì)算任務(wù)已經(jīng)完畢了,他只要把得到的結(jié)果全交給子函數(shù)就可以了,無需保存什么,子函數(shù)其實(shí)可以不需要再去創(chuàng)建一個(gè)棧幀,直接把就著當(dāng)前棧幀,把原先的數(shù)據(jù)覆蓋即可。相對的,如果是普通的遞歸,函數(shù)在遞歸調(diào)用之前并沒有完成全部計(jì)算,還需要調(diào)用遞歸函數(shù)完成后才能完成運(yùn)算任務(wù),比如return n * fact(n - 1);這句話,這個(gè)fact(n)在算完fact(n-1)之后才能得到n * fact(n - 1)的運(yùn)算結(jié)果然后才能返回。
綜上所述,編譯器對尾遞歸的優(yōu)化實(shí)際上就是當(dāng)他發(fā)現(xiàn)你丫在做尾遞歸的時(shí)候,就不會(huì)去不斷創(chuàng)建新的棧幀,而是就著當(dāng)前的棧幀不斷的去覆蓋,一來防止棧溢出,二來節(jié)省了調(diào)用函數(shù)時(shí)創(chuàng)建棧幀的開銷,用《算法精解》里面的原話就是:“When a compiler detects a call that is tail recursive, it overwrites the current activation record instead of pushing a new one onto the stack.”
第三個(gè)問題,優(yōu)化工作交給編譯器還是交給自己?
這個(gè)怎么說呢,據(jù)網(wǎng)上查閱,java,C#和python都不支持編譯環(huán)境自動(dòng)優(yōu)化尾遞歸,這種情況下,當(dāng)然是別用遞歸效率最高,可以看下這里http://www.cnblogs.com/Alexander-Lee/archive/2010/09/16/1827587.html。但是對于C語言來說,編譯器白提供的服務(wù),用了也不差,畢竟遞歸代碼會(huì)好理解一點(diǎn),但換句話說,如果寫到尾遞歸這份上了,變成非遞歸已經(jīng)很好實(shí)現(xiàn)了,完全可以用循環(huán)來搞定,所以呢,這個(gè)時(shí)候,就看個(gè)人喜好了。
注:
老趙 大神也寫過一篇關(guān)于尾遞歸的文章,不過是用C#描述的,我沒怎么看,感興趣可以了解下。http://www.cnblogs.com/JeffreyZhao/archive/2009/03/26/tail-recursion-and-continuation.html

總結(jié)

以上是生活随笔為你收集整理的浅谈尾递归的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。