Python之递归函数
前言
說(shuō)到遞歸,如果是從其他編程語(yǔ)言轉(zhuǎn)到 Python 的童鞋對(duì)這個(gè)詞一定不會(huì)陌生,在很多情況下,使用遞歸可以提高程序的可讀性,雖然可以完全避免編寫(xiě)遞歸函數(shù),轉(zhuǎn)而使用循環(huán)來(lái)代替,但是作為程序猿,至少必須要能夠讀懂其他人編寫(xiě)的遞歸算法和函數(shù)吧。OK,廢話不多說(shuō),來(lái)看一下 Python 中遞歸函數(shù)的寫(xiě)法。
定義
所謂遞歸,就是調(diào)用函數(shù)自身。
簡(jiǎn)單的說(shuō)就是函數(shù)自己調(diào)用自己。遞歸可能難以理解,也可能非常簡(jiǎn)單,這取決于對(duì)它的熟悉程度。
下面是一個(gè)遞歸函數(shù)的定義:
這個(gè)遞歸定義顯然什么都沒(méi)有做,如果運(yùn)行該函數(shù)的結(jié)果就是一段時(shí)間后程序就崩掉了。因?yàn)槊看握{(diào)用函數(shù)都將會(huì)消耗一些內(nèi)存,當(dāng)內(nèi)存爆滿就自然就掛了。
這個(gè)函數(shù)中的遞歸成為無(wú)窮遞歸,就好比一個(gè) while 死循環(huán),從理論上說(shuō)它將永遠(yuǎn)不會(huì)結(jié)束,這顯然不是我們想要的結(jié)果。
所以正常的遞歸函數(shù)通常包含以下兩個(gè)部分;
1.基線條件(針對(duì)最小的問(wèn)題):滿足這種條件時(shí)函數(shù)將直接返回一個(gè)值。
2.遞歸條件:包含一個(gè)或多個(gè)調(diào)用,這些調(diào)用旨在解決問(wèn)題的一部分。
這里的關(guān)鍵是,通過(guò)將問(wèn)題分解為較小的部分,可避免遞歸沒(méi)完沒(méi)了,因?yàn)閱?wèn)題終將被分解成基線條件可以解決的最小問(wèn)題。
OK,以上的定義和描述可能對(duì)于一個(gè)剛接觸遞歸的人來(lái)說(shuō)有些難以理解,接下來(lái)通過(guò)幾個(gè)示例來(lái)看看遞歸的用法。
遞歸經(jīng)典案例
計(jì)算階乘
階乘定義:n 的階乘為 n*(n-1)*(n-2)*…*1
那么要計(jì)算階乘,用傳統(tǒng)的循環(huán)方式寫(xiě)法如下:
上述循環(huán)的思路大概是:首先將 result 設(shè)置成 n,然后通過(guò)循環(huán),將 result 依次乘以1~(n-1)的每個(gè)數(shù)字,最后返回結(jié)果。
而通過(guò)遞歸的方式如何實(shí)現(xiàn)呢,再看階乘的算法,n 的階乘其實(shí)相當(dāng)于 n 乘以(n-1)的階乘,而1的階乘為1。
通過(guò)以上分析,來(lái)看看通過(guò)遞歸來(lái)實(shí)現(xiàn)階乘的寫(xiě)法:
很明顯,通過(guò)遞歸來(lái)實(shí)現(xiàn)同樣算法,代碼非常簡(jiǎn)單,并且可讀性也很好。這是前述定義的直接實(shí)現(xiàn),只是別忘了函數(shù)調(diào)用factorial(n)和factorial(n-1) 是不同的實(shí)體。
計(jì)算冪
定義一個(gè)數(shù)字的整數(shù)次冪,有多種方式,先來(lái)看個(gè)簡(jiǎn)單的定義:power(x,n)(x 的 n 次冪)是將數(shù)字 x 自乘以 n-1次的結(jié)果,即將 n 個(gè) x 相乘。
傳統(tǒng)的寫(xiě)法,通過(guò)循環(huán)來(lái)實(shí)現(xiàn):
這是一個(gè)非常簡(jiǎn)單的小型函數(shù),可將定義修改成遞歸的形式:
對(duì)于任何數(shù)字的0次冪都是1
當(dāng) n 大于0時(shí),power(x,n)為 x和 power(x,n-1)的乘積。
那么來(lái)看看遞歸的寫(xiě)法:
def power(x,n):if n == 0:return 1else:return x*power(x,n-1)二分法查找
二分法查找,這是一個(gè)非常經(jīng)典的查找算法,所謂的二分法,就是讓每次查找的范圍減半,這樣查找效率非常的高,比如說(shuō)一個(gè)猜數(shù)游戲,從1~100數(shù)字中猜出對(duì)方想好的一個(gè)數(shù)字,如果從1到100一個(gè)個(gè)的猜,肯定能猜對(duì),最多會(huì)猜100次,那么最少需要猜多少次呢,通過(guò)二分法實(shí)際上只需要7次就能猜出正確答案。
結(jié)合二分法的定義引出遞歸的定義和實(shí)現(xiàn)。
1.如果上限和下限相同,就說(shuō)明它們都指向數(shù)字所在的位置,因此將該數(shù)字返回。
2.否則,找出區(qū)間的中間位置(上限和下限的平均值),再將數(shù)字確定是在左半部分還是有半部分,然后繼續(xù)在數(shù)字所在的那部分中查找。
OK,接下來(lái)看看遞歸實(shí)現(xiàn)二分法算法:
def search(seq,number,lower = 0,upper = None):if upper is None:upper = len(seq) - 1if lower == upper:assert number == seq[upper]return upperelse:middle = (lower + upper) // 2if number > seq[middle]:return search(seq,number,middle + 1,upper)else:return search(seq,number,lower,middle)這里將上限和下限值定義成可選,如果不指定上下限值,那么默認(rèn)為序列的開(kāi)頭和結(jié)尾位置。該遞歸的實(shí)現(xiàn)完全由上面的定義一致。
來(lái)看看效果:
返回結(jié)果:
[1, 23, 24, 32, 35, 38, 76, 89] 3 7二分法在對(duì)于一個(gè)非常大的序列中使用效率非常高,如果使用循環(huán)的方式一個(gè)個(gè)的去找,對(duì)于序列中元素較少的情況下還好,如果數(shù)據(jù)量非常大,查詢效率就很低了。
由此可見(jiàn),遞歸的寫(xiě)法非常簡(jiǎn)潔,合理使用遞歸程序的可讀性將會(huì)大大的提高。
總結(jié)
以上是生活随笔為你收集整理的Python之递归函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python之函数的收集参数和分配参数用
- 下一篇: 简单理解Python中的if __nam