一個函數只能有一個返回值,具有返回值的遞歸函數若平行的多次調用自身,那么將會產生多個返回值,這是一個bug。在樹形多分枝結構的遞歸中對兩種方式進行比較討論。
例如求樹高的兩種寫法:
1 struct Node{ 2 int val; 3 Node* child; 4 Node* sibling; 5 Node(){ 6 child=NULL; 7 sibling=NULL; 8 } 9 }; 10 int height(Node *root){ 11 if(root){ 12 int maxh=0; 13 for(Node *p=root;p;p=p->sibling){ 14 int tmp=height(p->child); 15 if(maxh<tmp){ 16 maxh=tmp; 17 } 18 } 19 return maxh+1; 20 } 21 return 0; 22 }
1 int maxh=0; 2 void height(Node *root,int h){ 3 if(root){ 4 for(Node* p=root;p;p=p->sibling){ 5 height(p->child,h+1); 6 } 7 }else{ 8 if(maxh<h){ 9 maxh=h; 10 } 11 } 12 }
前者使用帶有返回值的遞歸形式,利用返回值進行計算;后者采用傳參的形式,利用參數進行計算。之所以能有這兩種寫法,是因為樹高要求每條路徑的最深,再進行比較,是到最深處才能確定的。也是唯一的解。而其除了這些有唯一解的遞歸問題,例如遞歸建立二叉樹的多分枝層次問題等,就很難使用帶有返回值的遞歸求解。帶有返回值的遞歸,由淺入深,在最深處達到出口進行計算后能逐層返回淺層。注意返回,這就需要返回一個唯一確定的值了。
p.s.說明一下何為唯一,遞歸到最深層后,逐層向淺層返回值,必有確定的一條路徑,稱為唯一。
一個關鍵性的點--具象的多分枝遞歸是一個怎樣的過程,前面的文章中提到過多分枝的遞歸問題生成樹形結構。故具體的可以參考圖的深度優先遍歷,遞歸是以一條路走到黑,走不動再返回分岔口再選擇另一條路,最終遍歷多分枝的所有路徑的方法,類似我們走迷宮的暴力解法。每條路徑不能直接進行傳值等交互操作但是,但我們可以選擇路徑,選擇符合我們條件的路徑的結果。對比於圖的廣度優先遍歷,可以說深度,也就是遞歸的方式是一個線性化的路線,只能父子節點進行交互,兄弟節點在不同的路徑上故被隔離了;而層次遍歷則一次可以訪問所有的節點,也就產生了兄弟節點的關聯。
下面討論剛才提到的難以寫成帶有返回值的遞歸的問題。
多分枝層次問題:
建立樹,例如二叉樹有兩種形式,一種是層次建立,不在本次遞歸的主題中討論;另一種是遞歸建立,對於每個節點,先建立根節點,再建立左右子樹。算法生成的樹的順序即和先序遍歷相同,也是“線性”地產生了二叉樹。這個多分枝問題直到最深處二叉樹建立完畢就結束了,並沒有向淺層返回的確定的路徑(值。
addition:求樹的路徑數(二叉樹,樹自己寫循環
1 int paths(node root){ 2 if(root!=null){ 3 if(root.left==null&&root.right==null) 4 return 1; 5 return paths(root.left)+ paths(root.right); 6 } 7 return 0; 8 }