遞歸應該是初學者最難啃的一塊骨頭,很多人也是半懂不懂,結果學到很深的境地也會因為自己基礎不好,導致發展太慢。
因此我希望初學者還是深刻理解遞歸及深搜,這樣以后再繼續向前學。
遞歸,我們把這個字分為兩個部分:
遞:
所謂遞即向下傳遞,換一種理解方式就是間接或直接地調用自己本身,且遞歸通常把一個大型復雜的問題層層轉換成一個規模較小的子問題,所以遞的意思便是把問題轉變成一個個的字問題,然后逐步解決。
歸:
歸也是初學者不明白的地方之一,難道解決完子問題就完了嗎,不存在的,如果你想用子問題的值,那歸的作用就體現出來了,我們可以先“遞”,然后在每個最小的問題的解決的時候返回最小的問題的值,最后解決父問題。但是要注意的是遞歸是有邊界的,即最小的子問題便是他的邊界。
如果遞歸有這么”簡單“就好了,但是可能有些人對遞歸的理解也僅僅到這種程度,如果上面你還不明白下面有例子。
上文的遞歸僅僅是對所有遞歸的一個概括,但遞歸其實可以分為兩大類:
尾部遞歸:
這個也是很好理解的,如果一個遞歸函數的尾部才是調用自己,那就是尾部遞歸,這個比較好理解
比如下面這個例子:
int jiecheng(int n) { if(n==1) return 1; else return jiecheng(n-1)*n; }
這個函數顧名思義求n的階乘,我們先進行一波小小的數學推理,一個數的階乘就是(這個數-1)的階乘乘上這個數。並因此可以繼續向下求這個數-1的階乘(這便是”遞“),
直到這個數到1時,便開始”歸“,不斷返回值,到最后返回這個數的階乘。
emmm,這似乎很簡單,但是還有一個比較難的遞歸。
中間遞歸:
中間遞歸和平常的遞歸不一樣的是在遞歸函數中,遞歸到下一層的語句后面還有語句,這時候在歸上來的時候就不僅僅再返回值了,還會再執行上一層的語句,參數也執行上一次的參數,這種遞歸常常在搜索中被實現。
比如如果有這樣的幾個房間,每個房間都有兩個門,有一個門都可以進入下一個房間,而另一個門則可以進入另一個房間,在這些房間里尋找寶石,如果找到就原路返回。
假設共有4個房間,且寶石在第四個房間里。
那這個題的尋找路徑便為:
進入第一個房間,進入第二個房間,進入第三個房間,進入第四個房間,找到了。回到第三個房間,回到第二個房間,回到第一個房間。
拿我們的代碼就是
void 找寶石(int 當前深度) { 進入(深度); if(找到寶石) 拿走寶石; else 找寶石(當前深度加一);//這便是遞歸函數。 離開(當前深度); }
這是我們寫的代碼,但是實際上被執行的代碼是
void 找寶石(2) { 進入(2); if(找到寶石) 拿走寶石; else { 進入(3); if(找到寶石) 拿走寶石; else { 進入(4) if(找到寶石) 拿走寶石;//找到了。 離開(4); } 離開(3); } 離開(2); }
如果你還不理解,別急,再看一遍,如果再不理解,可能是我講的不好,還是看紫書吧。