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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python汉诺塔递归算法_Python文摘:汉诺塔问题与递归算法

發(fā)布時(shí)間:2024/7/23 python 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python汉诺塔递归算法_Python文摘:汉诺塔问题与递归算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

歷史傳說:

在世界中心貝拿勒斯(在印度北部)的圣廟里,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創(chuàng)造世界的時(shí)候,在其中一根針上從下到上地穿好了由大到小的64片金片,這就是所謂的漢諾塔。不論白天黑夜,總有一個(gè)僧侶在按照下面的法則移動這些金片:一次只移動一片,不管在哪根針上,小片必須在大片上面。僧侶們預(yù)言,當(dāng)所有的金片都從梵天穿好的那根針上移到另外一根針上時(shí),世界就將在一聲霹靂中消滅,而梵塔、廟宇和眾生也都將同歸于盡。

不管這個(gè)傳說的可信度有多大,如果考慮一下把64片金片,由一根針上移到另一根針上,并且始終保持上小下大的順序。這需要多少次移動呢?這里需要遞歸的方法。假設(shè)有n片,移動次數(shù)是f(n).顯然f⑴=1,f⑵=3,f⑶=7,且f(k+1)=2*f(k)+1。此后不難證明f(n)=2^n-1。n=64時(shí),f(64)= 2^64-1=18446744073709551615。假如每秒鐘一次,共需多長時(shí)間呢?一個(gè)平年365天有 31536000 秒,閏年366天有31622400秒,平均每年31556952秒,計(jì)算一下,18446744073709551615/31556952=584554049253.855年

這表明移完這些金片需要5845億年以上,而地球存在至今不過45億年,太陽系的預(yù)期壽命據(jù)說也就是數(shù)百億年。真的過了5845億年,不說太陽系和銀河系,至少地球上的一切生命,連同梵塔、廟宇等,都早已經(jīng)灰飛煙滅。

***********************************************************************************************************************************************************************************

漢諾塔問題的限制條件:

1.在小圓盤上不能放大圓盤。

2.在三根柱子之間一回只能移動一個(gè)圓盤。

3.只能移動在最頂端的圓盤。

首先,我們從簡單的例子開始分析,然后再總結(jié)出一般規(guī)律。

當(dāng)n = 1的時(shí)候,即此時(shí)只有一個(gè)盤子,那么直接將其移動至C即可。移動過程就是 A -> C

當(dāng)n = 2的時(shí)候,這時(shí)候有兩個(gè)盤子,那么在一開始移動的時(shí)候,我們需要借助B柱作為過渡的柱子,即將A柱最上面的那個(gè)小圓盤移至B柱,然后將A柱底下的圓盤移至C柱,最后將B柱的圓盤移至C柱即可。那么完整移動過程就是A -> B , A -> C , B -> C

當(dāng)n = 3的時(shí)候,那么此時(shí)從上到下依次擺放著從小到大的三個(gè)圓盤,根據(jù)題目的限制條件:在小圓盤上不能放大圓盤,而且把圓盤從A柱移至C柱后,C柱圓盤的擺放情況和剛開始A柱的是一模一樣的。所以呢,我們每次移至C柱的圓盤(移至C柱后不再移到其他柱子上去),必須是從大到小的,即一開始的時(shí)候,我們應(yīng)該想辦法把最大的圓盤移至C柱,然后再想辦法將第二大的圓盤移至C柱......然后重復(fù)這樣的過程,直到所有的圓盤都按照原來A柱擺放的樣子移動到了C柱。

那么根據(jù)這樣的思路,問題就來了:

如何才能夠?qū)⒆畲蟮谋P子移至C柱呢?

那么我們從問題入手,要將最大的盤子移至C柱,那么必然要先搬掉A柱上面的n-1個(gè)盤子,而C柱一開始的時(shí)候是作為目標(biāo)柱的,所以我們可以用B柱作為"暫存"這n-1個(gè)盤子的過渡柱,當(dāng)把這n-1的盤子移至B柱后,我們就可以把A柱最底下的盤子移至C柱了。

而接下來的問題是什么呢?

我們來看看現(xiàn)在各個(gè)柱子上盤子的情況,A柱上無盤子,而B柱從上到下依次擺放著從小到大的n-1個(gè)盤子,C柱上擺放著最大的那個(gè)盤子。

所以接下來的問題就顯而易見了,那就是要把B柱這剩下的n-1個(gè)盤子移至C柱,而B柱作為過渡柱,那么我們需要借助A柱,將A柱作為新的"過渡"柱,將這n-1個(gè)盤子移至C柱。

*********************************************************************************************************************************************************************

作者:Adherer

來源:CSDN

原文:https://blog.csdn.net/liujian20150808/article/details/50793101

版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!

*********************************************************************************************************************************************************************

該問題可以分解成以下子問題:

第一步:將n-1個(gè)盤子從A柱移動至B柱(借助C柱為過渡柱)

第二步:將A柱底下最大的盤子移動至C柱

第三步:將B柱的n-1個(gè)盤子移至C柱(借助A柱為過渡柱)

解:(1)n == 1

第1次 1號盤 A---->C sum = 1 次

(2) n == 2

第1次 1號盤 A---->B

第2次 2號盤 A---->C

第3次 1號盤 B---->C sum = 3 次

(3)n == 3

第1次 1號盤 A---->C

第2次 2號盤 A---->B

第3次 1號盤 C---->B

第4次 3號盤 A---->C

第5次 1號盤 B---->A

第6次 2號盤 B---->C

第7次 1號盤 A---->C sum = 7 次

不難發(fā)現(xiàn)規(guī)律:1個(gè)圓盤的次數(shù) 2的1次方減1

2個(gè)圓盤的次數(shù) 2的2次方減1

3個(gè)圓盤的次數(shù) 2的3次方減1

。 。 。 。 。

n個(gè)圓盤的次數(shù) 2的n次方減1

故:移動次數(shù)為:2^n - 1

n的階乘問題

再說一個(gè)例子:計(jì)算n的階乘

f(n) = n!

其遞歸算法如下:

int factorial(int n){

if(n == 1)

return 1;

else

return n * factorial(n-1);

}

這段程序加載到內(nèi)存的分配圖如下:

(圖片來源于“碼農(nóng)翻身”公眾號)

由于遞歸是函數(shù)自身調(diào)用自身,所以程序被編譯后代碼段中只有一份代碼。遞歸調(diào)用是如何進(jìn)行的呢?注意看堆棧中的棧幀啊, 每個(gè)棧幀就代表了被調(diào)用中的一個(gè)函數(shù), 這些函數(shù)棧幀以先進(jìn)后出的方式排列起來,就形成了一個(gè)棧, 棧幀的結(jié)構(gòu)如下圖所示:

(圖片來源于“碼農(nóng)翻身”公眾號)

相信大家還記得《數(shù)據(jù)結(jié)構(gòu)》(嚴(yán)蔚敏版)一書中提到的“工作記錄”就是指函數(shù)棧幀。棧頂指針被稱為“當(dāng)前環(huán)境指針”。忽略到其他內(nèi)容, 只關(guān)注輸入?yún)?shù)和返回值的話,階乘函數(shù)factorial(4)的工作棧如下圖所示:

(圖片來源于“碼農(nóng)翻身”公眾號)

其計(jì)算過程如下圖所示:

(圖片來源于“碼農(nóng)翻身”公眾號)

注意, 每個(gè)遞歸函數(shù)必須得有個(gè)終止條件, 要不然就會發(fā)生無限遞歸了, 永遠(yuǎn)都出不來了。

當(dāng)然針對于此遞歸算法,對于n的值是有限制的。因?yàn)槎褩H萘渴怯邢薜?#xff0c;如果n值太大程序會崩掉。

該如何解決呢?從上面的代碼中可以知道“factorial(n) = n * factorial(n-1 )” ,這個(gè)計(jì)算式是整個(gè)程序的核心。 圖中每個(gè)棧幀都需要記錄下當(dāng)前的n的值, 還要記錄下一個(gè)函數(shù)棧幀的返回值, 然后才能運(yùn)算出當(dāng)前棧幀的結(jié)果。 也就是說使用多個(gè)棧幀是不可避免的。

可以使用下面的遞歸算法:

int factorial(int n,int result){

if(n == 1){

return result;

}

else{

return factorial(n-1,n * result);

}

}

注意函數(shù)的最后一個(gè)語句, 就不是 n * factorial(n-1) 了, 而是直接調(diào)用factorial(....) 這個(gè)函數(shù)本身, 這就帶來了巨大的好處。

計(jì)算過程如下:

當(dāng)執(zhí)行到factorial(1, 24)的時(shí)候直接就可以返回結(jié)果了。這就是妙處所在了,計(jì)算機(jī)發(fā)現(xiàn)這種情況,只用一個(gè)棧幀就可以搞定這些計(jì)算,無論n有多大。

(圖片來源于“碼農(nóng)翻身”公眾號)

這就是所謂的“尾遞歸”了, 當(dāng)遞歸調(diào)用是函數(shù)體中最后執(zhí)行的語句并且它的返回值不屬于表達(dá)式一部分時(shí), 這個(gè)遞歸就是尾遞歸。

現(xiàn)代的編譯器就會發(fā)現(xiàn)這個(gè)特點(diǎn), 生成優(yōu)化的代碼, 復(fù)用棧幀。 第一個(gè)算法中因?yàn)橛袀€(gè)n * factorial(n-1) , 雖然也是遞歸,但是遞歸的結(jié)果處于一個(gè)表達(dá)式中,還要做計(jì)算, 所以就沒法復(fù)用棧幀了,只能一層一層的調(diào)用下去。

總結(jié)

以上是生活随笔為你收集整理的python汉诺塔递归算法_Python文摘:汉诺塔问题与递归算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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