遞迴函式——頭遞迴和尾遞迴
學習總結自《像程式設計師一樣思考》V.Anton Spraul 著,徐波 譯
遞迴,也就是一個函式直接或間接呼叫自身。
一般來說,遞迴可以分為直接遞迴和間接遞迴。直接遞迴,是指函式自己呼叫自己的情況,而間接遞迴,是指呼叫其他函式時,在其他函式中又呼叫了自己的情況。
現在,主要將遞迴分為頭遞迴和尾遞迴來學習。
1.概念
頭遞迴:遞迴發生在函式的其他處理程式碼之前(或理解為,遞迴發生在函式的頭部或頂部)
尾遞迴:與頭遞迴正好相反,遞迴發生在函式其他處理程式碼的後面(或理解為,遞迴發生在函式的尾部)
2.例子
1)多少隻鸚鵡
現在有5個連續的火車站臺(A,B,C,D,E),5個站臺裡都有鸚鵡,每個站臺只能與直接相鄰的站臺通話,而負責人在A站臺,問負責人如何知道這5個站臺的鸚鵡總數。
方法1:
1》A站臺計數他的站臺的鸚鵡數量,7只鸚鵡;
2》A站臺和B站臺聯絡,告訴B站臺當前的鸚鵡總數(一個站臺),7只鸚鵡;
3》B站臺計數他的站臺的鸚鵡數量,5只鸚鵡;
4》B站臺和C站臺聯絡,告訴C站臺當前的鸚鵡總數(前兩個站臺),12只鸚鵡;
5》C站臺計數他的站臺的鸚鵡數量,3只鸚鵡;
6》C站臺和D站臺聯絡,告訴D站臺當前的鸚鵡總數(前三個站臺),15只鸚鵡;
7》D站臺計數他的站臺的鸚鵡總數,10只鸚鵡;
8》D站臺和E站臺聯絡,告訴E站臺當前的鸚鵡總數(前四個站臺),25只鸚鵡;
9》E站臺計數他的站臺的鸚鵡總數,2只鸚鵡,得出5個站臺的總鸚鵡數量是27只;
10》E站臺向D站臺反饋:鸚鵡總數是27只;
11》D站臺向C站臺反饋:鸚鵡總數是27只;
12》C站臺向B站臺反饋:鸚鵡總數是27只;
11》B站臺向A站臺反饋:鸚鵡總數是27只。
方法1採用的步驟提取如下:
1》對本站臺的鸚鵡數量計數
2》把上一個站臺的總鸚鵡數量與本站臺的鸚鵡數量相加
3》與下一個站臺通話,彙報當前的鸚鵡總數
4》最後等待總結過的反饋,待下一個站臺將鸚鵡總數彙報給本站臺後,然後把這個結果向上一個站臺彙報。
方法2:
1》A站臺與B站臺通話:到你的站臺為止的鸚鵡總數是多少;
2》B站臺與C站臺通話:到你的站臺為止的鸚鵡總數是多少;
3》C站臺與D站臺通話:到你的站臺為止的鸚鵡總數是多少;
4》D站臺與E站臺通話:到你的站臺為止的鸚鵡總數是多少;
5》E是最後一個站臺,收到D的訊息後,計數他的站臺的鸚鵡數量,2只鸚鵡;
6》E與D通話:目前為止,鸚鵡總數2只;
6》D站臺計數他的站臺的鸚鵡數量,10只鸚鵡,得到鸚鵡總數12只鸚鵡;
7》D與C通話:目前為止,鸚鵡總數12只;
8》C站臺計數他的站臺的鸚鵡數量,3只鸚鵡,得到鸚鵡總數15只鸚鵡;
9》C與B通話:目前為止,鸚鵡總數15只;
10》B站臺計數他的站臺的鸚鵡數量,5只鸚鵡,得到鸚鵡總數20只鸚鵡;
11》B與A通話:目前為止,鸚鵡總數20只;
12》A站臺計數他的站臺的鸚鵡數量,7只鸚鵡,得到鸚鵡總數27只。
方法2採用的步驟提取如下:
1》與下一站通話;
2》對當前站點的鸚鵡計數;
3》把當前站臺的鸚鵡數量加上下一站點反饋的鸚鵡總數;
4》把相加所得的結果彙報給上一個站臺。
從這個例子可以看出,方法1是先對本站點的鸚鵡數量進行處理後,再去詢問下一個站臺的鸚鵡數量,是屬於尾遞迴的情況,而方法2是先進入到下一個站臺,讓下一個站臺處理鸚鵡數量,得到下一個站臺的鸚鵡數量後,再對該站臺的鸚鵡數量進行計數相加,屬於頭遞迴的情況。
3.結論
頭遞迴與尾遞迴相比,將處理過程置後,從遞迴的目的出發,將大問題細化成小問題,細化到可以解決的程度後,將結果一層層反饋,而較大細度的問題可以直接將該結果作為已知資料進行計算使用,使遞迴過程更加方便清晰。尾遞迴過程是先對當前細度的問題進行處理,但是該結果只是一個暫時值,需要將問題一層層細化後,每層對當前的暫時值進行計算操作,得到最終的結果,可以看做是一個不斷修正的過程,所以尾遞迴過程相對頭遞迴來說,計算較慢,所佔資源也會較多。所以,建議採用頭遞迴。
一般來說,頭遞迴更加體現了遞迴的思想,大遞迴思想,在使用遞迴解決問題時,我們的思維應該有別於其他的函式的實現過程,在實現其他函式時,我們會細化各個過程,用程式化的思維來思考各個步驟,這個思維用在遞迴函式時,將會以尾遞迴的方式呈現出來,因為,我們都想盡可能完成函式功能,就會不自覺的將可以實現的功能寫在了前面。大遞迴的思想就是讓我們多在意遞迴函式的意義,我們在用遞迴函式實現某一功能時,應該時時牢記該遞迴函式的功能,多關注該問題與子問題之間的關係,儘可能用頭遞迴的方式實現遞迴函式。