遞歸的思想主要是能夠重復(fù)某些動作,比如簡單的階乘,次方,回溯中的八皇后,數(shù)獨(dú),還有漢諾塔,分形。

創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的晉州網(wǎng)站設(shè)計(jì)、移動媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
由于堆棧的機(jī)制,一般的遞歸可以保留某些變量在歷史狀態(tài)中,比如你提到的return x * power..., 但是某些或許龐大的問題或者是深度過大的問題就需要盡量避免遞歸,因?yàn)榭赡軙R绯觥_€有一個問題是~python不支持尾遞歸優(yōu)化!!!!所以~還是盡量避免遞歸的出現(xiàn)。
def power(x, n)
if n 0:
return 1
return x * power(x, n - 1)
power(3, 3)
3 * power(3, 2)
3 * (3 * power(3, 1))
3 * (3 * (3 * power(3, 0)))
3 * (3 * (3 * 1)) 這里n = 0, return 1
3 * (3 * 3)
3 * 9
27
當(dāng)函數(shù)形參n=0的時候,開始回退~直到第一次調(diào)用power結(jié)束。
lambda不好寫,寫了前兩個,把-2改為-7,改成-7后,我試過x必須大于4。-2時x可以從1開始
#遞歸
def?power(n,?x):
if?abs(1/pow(n,?x))abs(pow(10,?-2)):
return?0#回歸條件
else:
m?=?n?+?1#遞歸因子
if(n%2==1):
return?1/pow(n,?x)+power(m,?x)#求和奇正
else:
return?-1/pow(n,?x)+power(m,?x)#求和偶負(fù)
def?power2(n,?x):
sum?=?0
while(1/pow(n,x)abs(pow(10,?-2))):
if?(n?%?2?==?1):
sum+=?1?/?pow(n,?x)
else:
sum+=-1?/?pow(n,?x)
n?+=?1??#?遞增
return?sum
if?__name__?==?"__main__":
x?=?input("請輸入冪數(shù)")
x?=?int(x)
n?=?1
sum?=?power(n,?x)
print(sum)
n=1
sum?=?power2(n,?x)
print(sum)
例如上面的例子,實(shí)現(xiàn)一個整形集合的累加。假設(shè)lst = [1,2,3,4,5],實(shí)現(xiàn)累加的方式有很多:
第一種:用sum函數(shù)。
sum(lst)
第二種:循環(huán)方式。
def customer_sum(lst):
result = 0
for x in lst:
result+=x
return result
def customer_sum(lst):
result = 0
while lst:
temp = lst.pop(0)
result+=temp
return result
if name ==" main ":
lst = [1,2,3,4,5]
print customer_sum(lst)
第三種:遞推求和
def add(lst,result):
if lst:
temp = lst.pop(0)
temp+=result
return add(lst,temp)
else:
return result
if name ==" main ":
lst = [1,2,3,4,5]
print add(lst,0)
第四種:reduce方式
lst = [1,2,3,4,5]
print reduce(lambda x,y:x+y,lst)
lst = [1,2,3,4,5]
print reduce(lambda x,y:x+y,lst,0)
def add(x,y):
return x+y
print reduce(add, lst)
def add(x,y):
return x+y
print reduce(add, lst,0)
有一個序列集合,例如[1,1,2,3,2,3,3,5,6,7,7,6,5,5,5],統(tǒng)計(jì)這個集合所有鍵的重復(fù)個數(shù),例如1出現(xiàn)了兩次,2出現(xiàn)了兩次等。大致的思路就是用字典存儲,元素就是字典的key,出現(xiàn)的次數(shù)就是字典的value。方法依然很多
第一種:for循環(huán)判斷
def statistics(lst):
dic = {}
for k in lst:
if not k in dic:
dic[k] = 1
else:
dic[k] +=1
return dic
lst = [1,1,2,3,2,3,3,5,6,7,7,6,5,5,5]
print(statistics(lst))
第二種:比較取巧的,先把列表用set方式去重,然后用列表的count方法
def statistics2(lst):
m = set(lst)
dic = {}
for x in m:
dic[x] = lst.count(x)
lst = [1,1,2,3,2,3,3,5,6,7,7,6,5,5,5]
print statistics2(lst)
第三種:用reduce方式
def statistics(dic,k):
if not k in dic:
dic[k] = 1
else:
dic[k] +=1
return dic
lst = [1,1,2,3,2,3,3,5,6,7,7,6,5,5,5]
print reduce(statistics,lst,{})
或者
d = {}
d.extend(lst)
print reduce(statistics,d)
通過上面的例子發(fā)現(xiàn),凡是要對一個集合進(jìn)行操作的,并且要有一個統(tǒng)計(jì)結(jié)果的,能夠用循環(huán)或者遞歸方式解決的問題,一般情況下都可以用reduce方式實(shí)現(xiàn)。
函數(shù)的遞歸調(diào)用
遞歸問題是一個說簡單也簡單,說難也有點(diǎn)難理解的問題.我想非常有必要對其做一個總結(jié).
首先理解一下遞歸的定義,遞歸就是直接或間接的調(diào)用自身.而至于什么時候要用到遞歸,遞歸和非遞歸又有那些區(qū)別?又是一個不太容易掌握的問題,更難的是對于遞歸調(diào)用的理解.下面我們就從程序+圖形的角度對遞歸做一個全面的闡述.
我們從常見到的遞歸問題開始:
1 階層函數(shù)
#include iostream
using namespace std;
int factorial(int n)
{
if (n == 0)
{
return 1;
}
else
{
int result = factorial(n-1);
return n * result;
}
}
int main()
{
int x = factorial(3);
cout x endl;
return 0;
}
這是一個遞歸求階層函數(shù)的實(shí)現(xiàn)。很多朋友只是知道該這么實(shí)現(xiàn)的,也清楚它是通過不斷的遞歸調(diào)用求出的結(jié)果.但他們有些不清楚中間發(fā)生了些什么.下面我們用圖對此做一個清楚的流程:
根據(jù)上面這個圖,大家可以很清楚的看出來這個函數(shù)的執(zhí)行流程。我們的階層函數(shù)factorial被調(diào)用了4次.并且我們可以看出在調(diào)用后面的調(diào)用中,前面的調(diào)用并不退出。他們同時存在內(nèi)存中。可見這是一件很浪費(fèi)資源的事情。我們該次的參數(shù)是3.如果我們傳遞10000呢。那結(jié)果就可想而知了.肯定是溢出了.就用int型來接收結(jié)果別說10000,100就會產(chǎn)生溢出.即使不溢出我想那肯定也是見很浪費(fèi)資源的事情.我們可以做一個粗略的估計(jì):每次函數(shù)調(diào)用就單變量所需的內(nèi)存為:兩個int型變量.n和result.在32位機(jī)器上占8B.那么10000就需要10001次函數(shù)調(diào)用.共需10001*8/1024 = 78KB.這只是變量所需的內(nèi)存空間.其它的函數(shù)調(diào)用時函數(shù)入口地址等仍也需要占用內(nèi)存空間。可見遞歸調(diào)用產(chǎn)生了一個不小的開銷.
2 斐波那契數(shù)列
int Fib(int n)
{
if (n = 1)
{
return n;
}
else
{
return Fib(n-1) + Fib(n-2);
}
}
這個函數(shù)遞歸與上面的那個有些不同.每次調(diào)用函數(shù)都會引起另外兩次的調(diào)用.最后將結(jié)果逐級返回.
我們可以看出這個遞歸函數(shù)同樣在調(diào)用后買的函數(shù)時,前面的不退出而是在等待后面的結(jié)果,最后求出總結(jié)果。這就是遞歸.
3
#include iostream
using namespace std;
void recursiveFunction1(int num)
{
if (num 5)
{
cout num endl;
recursiveFunction1(num+1);
}
}
void recursiveFunction2(int num)
{
if (num 5)
{
recursiveFunction2(num+1);
cout num endl;
}
}
int main()
{
recursiveFunction1(0);
recursiveFunction2(0);
return 0;
}
運(yùn)行結(jié)果:
1
2
3
4
4
3
2
1
該程序中有兩個遞歸函數(shù)。傳遞同樣的參數(shù),但他們的輸出結(jié)果剛好相反。理解這兩個函數(shù)的調(diào)用過程可以很好的幫助我們理解遞歸:
我想能夠把上面三個函數(shù)的遞歸調(diào)用過程理解了,你已經(jīng)把遞歸調(diào)用理解的差不多了.并且從上面的遞歸調(diào)用中我們可以總結(jié)出遞歸的一個規(guī)律:他是逐級的調(diào)用,而在函數(shù)結(jié)束的時候是從最后面往前反序的結(jié)束.這種方式是很占用資源,也很費(fèi)時的。但是有的時候使用遞歸寫出來的程序很容易理解,很易讀.
為什么使用遞歸:
1 有時候使用遞歸寫出來的程序很容易理解,很易讀.
2 有些問題只有遞歸能夠解決.非遞歸的方法無法實(shí)現(xiàn).如:漢諾塔.
遞歸的條件:
并不是說所有的問題都可以使用遞歸解決,他必須的滿足一定的條件。即有一個出口點(diǎn).也就是說當(dāng)滿足一定條件時,程序可以結(jié)束,從而完成遞歸調(diào)用,否則就陷入了無限的遞歸調(diào)用之中了.并且這個條件還要是可達(dá)到的.
遞歸有哪些優(yōu)點(diǎn):
易讀,容易理解,代碼一般比較短.
遞歸有哪些缺點(diǎn):
占用內(nèi)存資源多,費(fèi)時,效率低下.
因此在我們寫程序的時候不要輕易的使用遞歸,雖然他有他的優(yōu)點(diǎn),但是我們要在易讀性和空間,效率上多做權(quán)衡.一般情況下我們還是使用非遞歸的方法解決問題.若一個算法非遞歸解法非常難于理解。我們使用遞歸也未嘗不可.如:二叉樹的遍歷算法.非遞歸的算法很難與理解.而相比遞歸算法就容易理解很多.
對于遞歸調(diào)用的問題,我們在前一段時間寫圖形學(xué)程序時,其中有一個四連同填充算法就是使用遞歸的方法。結(jié)果當(dāng)要填充的圖形稍微大一些時,程序就自動關(guān)閉了.這不是一個人的問題,所有人寫出來的都是這個問題.當(dāng)時我們給與的解釋就是堆棧溢出。就多次遞歸調(diào)用占用太多的內(nèi)存資源致使堆棧溢出,程序沒有內(nèi)存資源執(zhí)行下去,從而被操作系統(tǒng)強(qiáng)制關(guān)閉了.這是一個真真切切的例子。所以我們在使用遞歸的時候需要權(quán)衡再三.
首先我們要了解一下什么是遞歸。
遞歸法,遞歸法就是利用上一個或者上幾個狀態(tài)來求取當(dāng)前狀態(tài)的值(個人看法)。也可以說成函數(shù)自己調(diào)用自己的一種解決問題的策略。因此遞歸法通常是依托函數(shù)來實(shí)現(xiàn)的,遞歸函數(shù)總是會有一個出口,我們在解決遞歸問題時,只需要找出遞歸的關(guān)系式以及遞歸函數(shù)的出口(這兩個可以說是遞歸函數(shù)的核心了)。下面我將在這里舉求斐波那契值的例子帶領(lǐng)著大家具體的實(shí)踐一下遞歸法。
很顯然遞歸函數(shù)的遞推式是:fib(n) = fib(n-1)+fib(n-2)。
遞歸函數(shù)的出口是當(dāng)n為1時返回1,當(dāng)n為0時返回0。
最后遞歸函數(shù)的核心代碼就可以寫出了:
然后總的代碼就是:
具體思路如下:
語句 return fib(n-1)+fib(n-2)的意思就是向前求斐波那契值,直到n-1=1,n-2=0
因?yàn)橹挥械?個和第0個斐波那契值是確定的
例:
當(dāng)n=3時
第一次調(diào)用函數(shù)fib會執(zhí)行第三條語句(因?yàn)閚1)這樣求回返回fib(2)+fib(1)
第二次調(diào)用函數(shù)時,因?yàn)?1所有會返回fib(1)+fib(0);因?yàn)?不大于1,所以調(diào)用函數(shù)時
會執(zhí)行第二條語句返回1值。
第三次調(diào)用函數(shù),會執(zhí)行第一和第二條語句,依次返回0和1從而求得fib(2)
fib(3)=fib(2)+fib(1)
fib(2)=fib(1)+fib(0)
即fib(3)=fib(1)+fib(0)+fib(1)=2*fib(1)+fib(0)
文章標(biāo)題:python遞推函數(shù),遞推公式編程
文章分享:http://chinadenli.net/article32/heopsc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、手機(jī)網(wǎng)站建設(shè)、服務(wù)器托管、Google、標(biāo)簽優(yōu)化、搜索引擎優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)