最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

5.4 遞歸函數(shù)

2021-08-24 16:54 作者:海鷗之道  | 我要投稿

在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個函數(shù)在內(nèi)部調(diào)用自身本身,這個函數(shù)就是遞歸函數(shù)。

舉個例子,我們來計算階乘n! = 1 x 2 x 3 x ... x n,用函數(shù)fact(n)表示,可以看出:

所以,fact(n)可以表示為n x fact(n-1),只有n=1時需要特殊處理。

于是,fact(n)用遞歸的方式寫出來就是:

def fact(n):

? ?if n==1:

?? ????return 1

? ?return n * fact(n - 1)

上面就是一個遞歸函數(shù)??梢栽囋嚕?/p>

>>> fact(1)

1

>>> fact(5)

120

>>> fact(100)

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

如果我們計算fact(5),可以根據(jù)函數(shù)定義看到計算過程如下:


遞歸函數(shù)的優(yōu)點(diǎn)是定義簡單,邏輯清晰。理論上,所有的遞歸函數(shù)都可以寫成循環(huán)的方式,但循環(huán)的邏輯不如遞歸清晰。

使用遞歸函數(shù)需要注意防止棧溢出。在計算機(jī)中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個函數(shù)調(diào)用,棧就會加一層棧幀,每當(dāng)函數(shù)返回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會導(dǎo)致棧溢出??梢栽囋?code>fact(1000):

>>> fact(1000)?

Traceback (most recent call last):

?File "<stdin>", line 1, in <module>

?File "<stdin>", line 4, in fact ?...

?File "<stdin>", line 4, in fact?

RuntimeError: maximum recursion depth exceeded in comparison

解決遞歸調(diào)用棧溢出的方法是通過尾遞歸優(yōu)化,事實(shí)上尾遞歸和循環(huán)的效果是一樣的,所以,把循環(huán)看成是一種特殊的尾遞歸函數(shù)也是可以的。

尾遞歸是指,在函數(shù)返回的時候,調(diào)用自身本身,并且,return語句不能包含表達(dá)式。這樣,編譯器或者解釋器就可以把尾遞歸做優(yōu)化,使遞歸本身無論調(diào)用多少次,都只占用一個棧幀,不會出現(xiàn)棧溢出的情況。

上面的fact(n)函數(shù)由于return n * fact(n - 1)引入了乘法表達(dá)式,所以就不是尾遞歸了。要改成尾遞歸方式,需要多一點(diǎn)代碼,主要是要把每一步的乘積傳入到遞歸函數(shù)中:

def fact(n):

? ?return fact_iter(n, 1)

def fact_iter(num, product):

? ?if num == 1:

? ? ? ?return product

?? return fact_iter(num - 1, num * product)

可以看到,return fact_iter(num - 1, num * product)僅返回遞歸函數(shù)本身,num - 1num * product在函數(shù)調(diào)用前就會被計算,不影響函數(shù)調(diào)用。

fact(5)對應(yīng)的fact_iter(5, 1)的調(diào)用如下:

尾遞歸調(diào)用時,如果做了優(yōu)化,棧不會增長,因此,無論多少次調(diào)用也不會導(dǎo)致棧溢出。

遺憾的是,大多數(shù)編程語言沒有針對尾遞歸做優(yōu)化,Python解釋器也沒有做優(yōu)化,所以,即使把上面的fact(n)函數(shù)改成尾遞歸方式,也會導(dǎo)致棧溢出。

小結(jié)

  • 使用遞歸函數(shù)的優(yōu)點(diǎn)是邏輯簡單清晰,缺點(diǎn)是過深的調(diào)用會導(dǎo)致棧溢出。

  • 針對尾遞歸優(yōu)化的語言可以通過尾遞歸防止棧溢出。尾遞歸事實(shí)上和循環(huán)是等價的,沒有循環(huán)語句的編程語言只能通過尾遞歸實(shí)現(xiàn)循環(huán)。

  • Python標(biāo)準(zhǔn)的解釋器沒有針對尾遞歸做優(yōu)化,任何遞歸函數(shù)都存在棧溢出的問題。


5.4 遞歸函數(shù)的評論 (共 條)

分享到微博請遵守國家法律
德保县| 格尔木市| 榆树市| 拉萨市| 湖南省| 调兵山市| 庄河市| 克山县| 河间市| 福泉市| 婺源县| 阿拉善左旗| 龙口市| 珲春市| 乌兰察布市| 鄂托克旗| 社会| 越西县| 曲水县| 黔南| 蒲江县| 平凉市| 长沙市| 崇信县| 大同县| 红河县| 新津县| 吴忠市| 修水县| 庆城县| 涞源县| 平南县| 顺平县| 繁峙县| 柳州市| 定襄县| 无极县| 九江县| 黔江区| 莆田市| 灵山县|