遞歸算法定義及應用

最近在一些大牛那學了樹相關的遞歸算法,記錄一下。以便以後回顧。

1、何爲遞歸

遞歸就是循環定義,對於一個方法來說,就是自己調用自己。當一個問題的解決方案是重複的執行某個步驟,直到問題得到解決時。這時候你就想想,是不是該用遞歸去解決了。它能用幾行簡單的代碼去解決複雜的問題。

2、遞歸要點

當你選擇使用遞歸時,就必須考慮到以下幾個點,也是你寫代碼時必須遵循的要點(後續代碼會按照以下步驟去解決):
1、遞歸的終止條件。這是寫遞歸的必要條件,如果沒有終止條件,遞歸就無法結束,也就沒有意義去使用遞歸。
2、循環重複處理得邏輯。這也是你使用遞歸首先要考慮得,該問題是否是通過循環處理就可以得到解決。若是可以,它每次重複處理得內容是什麼。
3、返回值。每次遞歸需要返回一個值給上層或下層。給上下層使用。需要考慮他們需要得返回值是什麼。
那麼如何得出這三要點呢。舉例說明。比如,讓你計算1到100的和。採用遞歸方法代碼:

public class test {
	
	public static int add(int num,int i) {
		//終止條件
		if(i > 100) {
			return num;
		}
		//本層邏輯內容
		num = num + i;
		i = i + 1;
		//返回值
		return add(num,i);
	}
	
	public static void main(String args[]) {
		int sum= add(0,1);
		System.out.println(sum);
	}
}

首先,考慮第一個要點,什麼時候終止,1加到100。肯定到i >100得時候。就不需要繼續了,100爲終止條件。第二個要點。循環得處理邏輯是什麼。每一層需要幹什麼。需要將以前的值都加上.i是從1到100得。i逐層加1 .所以需要num=num+1;i = i+1;第三個要點,下層需要什麼。需要這一層得和。告訴下一層,我已經加到第4層了(1+2+3+4)。以此類推。
可能問題過於簡單,還體會不到遞歸得方便,也不好體現這三要點。下面通過樹與圖得相關總結來體現。

3、遞歸運用–樹相關算法。

1、樹得前序,中序,後序,深層遍歷
這是摘自leetcode上面的一道算法題-翻轉二叉樹。
在這裏插入圖片描述 這道題可以用來作爲遞歸和樹的排序的經典例題。借鑑了一些大佬的解題思路,所以想詳細分析一下。
首先分析一下這道題,翻轉二叉樹做的是什麼。將每個節點的左右子節點交換。有終止條件嗎?有,當子節點都爲空時結束。有循環重複處理的的嗎?有,交換左右子節點。返回值需要返回給上下層嗎?需要,每個節點的既可以是父節點,也可以是子節點,必然需要返回給上下層進行繼續交換。既然三個條件都滿足,那好,我們用遞歸開始解題。
不明白前序,中序,後序遍歷是啥樣的,自行百度一下。
1、前序遍歷。
代碼如下:

 //終止條件
        if(root == null){
            return null;
        }   
        //處理邏輯--前序遍歷,從上往下,交換左右
        TreeNode rightNode = root.right;
        root.right = invertTree(root.left);
        root.left= invertTree(rightNode );
        //返回值
        return root;
        

是不是看起來很簡單。但是寫的時候感覺無從下手。那麼回頭文章開始,三部曲。
第一步終止條件。節點爲空,直接返回,不處理,沒問題。
第二步處理邏輯。這部分比較重要。因爲遞歸歸根結底就是循環的做相同的事。那麼我只關注我這一層循環是幹了什麼就行。那麼對於任意一層,我們可以看作。父節點。左子節點,右子節點。需要做的就是,交換左右子節點。首先,保存左子節點。然後,令當前左子節點等於已經翻轉完的右子節點。接着,當前右子節點等於將剛剛保存的左子節點進行翻轉完的節點。也就是從上往下交換(前序遍歷)。
第三步返回值。就不用說了。返回當前節點。

2、中序遍歷。(只放代碼與註釋)

 public TreeNode invertTree(TreeNode root) {
        //終止條件
        if(root == null){
            return null;
        }   
        //處理邏輯
        TreeNode leftNode = invertTree(root.left);//遞歸找到最左節點
        root.left  = root.right;//處理父節點的左右交換
        root.right = leftNode;
        invertTree(root.left);//處理右節點,注意此時的右節點已經賦值給左節點了。
        //返回值
        return root;
    }

3、後序遍歷 (只放代碼與註釋)

 public TreeNode invertTree(TreeNode root) {
        //終止條件
        if(root == null){
            return null;
        }   
        //處理邏輯--後序遍歷從下往上。先解決左右,在往上遞歸
        TreeNode leftNode = invertTree(root.left);//遞歸找到左節點並保存
        root.left = invertTree(root.right);//將右節點賦值給左節點
        root.right = leftNode;//左節點賦值給右節點
        //返回值
        return root;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章