直接或間接地調用自身的算法稱爲遞歸算法。用函數自身給出定義的函數稱爲遞歸函數。
優點:結構清晰,可讀性強,而且容易用數學歸納法來證明算法的正確性,因此它爲設計算法、調試程序帶來很大方便。
缺點:遞歸算法的運行效率較低,無論是耗費的計算時間還是佔用的存儲空間都比非遞歸算法要多。
實例:Hanoi塔
問題描述
這個問題起源於一個類似傳說故事,在Hanoi這個地方有一個寺廟,這裏有3根柱子和64個大小不同的金碟子。每個碟子有一個孔可以穿過。所有的碟子都放在第一個柱子上,而且按照從上到下碟子的大小依次增大的順序擺設。如下圖:
現在,假定寺廟裏的僧侶要移動這些碟子,將它們從最左邊移動到最右邊的柱子上。不過移動的規則如下:
1. 每次只能從一個柱子的最上面移動一個碟子到另外一個柱子上。
2. 不能將大碟子放到小碟子的上面。
按照前面這個規則,我們該怎麼去移動這些碟子呢?假定單位時間內可以移動一片碟子,那麼最終移動這些碟子到目的柱子需要多長的時間呢?
問題分析
在分析這個問題的時候,我們可以先從一些簡單的場景來看怎麼來移動碟子保證可以達到目的。假定我們有3個碟子,那麼移動它們的過程如下圖:
我們假定柱子從左到右分別爲a, b, c。從前面移動碟子的步驟可以看到,我們要將a上面的兩個碟子先移動到中間的b柱子作爲過渡,然後再將最下面的柱子移動到目的c柱子,然後再將上面的兩個碟子移過來。在將最下面的碟子移動到c之前,首先的步驟1, 2, 3是將上面的碟子移動到柱子b。而將最下面碟子移動後,上面的兩個碟子又要移動一遍,不過是從b移動到c,只是藉助的柱子不一樣。
所以,從上面的過程,我們可以看到一個可以遞歸解決問題的思路,如下圖:
如圖所示,首先我們針對有n個碟子的柱子a,將n-1個碟子移動到柱子b。假定這個問題爲S(n)表示移動的步數,則上面的問題是S(n)的一個子問題S(n-1)。這一步對應步驟1。然後將最下面的碟子移動到柱子c,最後再將n-1個碟子移動到c。後面這一步也相當於S(n)的子問題S(n-1)。對應步驟3.它和前面第一步移動n-1個碟子唯一不同的地方在於第一步是藉助c將n-1個碟子從a移動到b,而最後這一步是藉助a將n-1個碟子從b移動到c。除了藉助的柱子和目的柱子不一樣,其他的都是一樣的。
代碼實現
public class Hanoi {public static void move(int n, char a, char b, char c) {
if(n == 0) return;
hanoi(n-1,a,c,b);
System.out.println("第"+n+"塊,從"+A+"移到"+C);
hanoi(n-1,b,a,c);
}
public static void main(String[] args) {
hanoi(3,'A','B','C');
}
}