對於不少程序員來講,寫遞歸程序是比較頭疼的一件事,即便是把程序看懂了,輪到本身寫的時候也是一臉懵逼,那麼到底寫遞歸有沒有方法論呢?固然!本文就將從數學概括法的角度教你如何寫遞歸程序。
程序員
有人會疑惑,不是說好寫遞歸嘛,怎麼扯到數學概括法了?別急慢慢往下看你就知道了。
首先咱們來溫習一下數學概括法的定義:函數
數學概括法:用於證實斷言對全部天然數成立。spa
證實過程:指針
- 證實對於N=1成立
- 證實N>1時:假設對於N-1成立,那麼對於N成立
咋一看你或許有點蒙,沒事,咱們來舉個例子你就差很少懂了。code
怎麼樣,總結一下就是:先證實第一個天然數成立,而後假設對於n-1成立,在用這個假設去推導證實對於n也成立
。遞歸
對於天然數的第一個數字到底是0仍是1,是一個學術界至今沒有統一的問題,咱們這裏使用1做爲天然數的第一個數。ip
接下來重點來了!!!咱們來看看如何用遞歸寫上面那個例子get
是否是驚人的類似啊!原來遞歸的思路和數學概括法的證實思路是同樣的啊!
鋪墊了這麼多,終於引出咱們今天要講的遞歸書寫方法論。
數學
先寫遞歸的主體部分,再回頭寫邊界(一行行讀主體部分的代碼,尋找特殊的邊界狀況)it
這裏的1並非狹義的,比方說若是二分查找的時候,每次縮小一半的規模也是能夠的
上面四點很是重要,爲了幫助你們理解,接下來我舉幾個例子讓你們熱熱身。
咱們想要建立一個五節點的單向鏈表(以下圖所示):
該怎麼作呢?首先咱們先假設若是已經獲得了後四個節點的鏈表:
那麼此時咱們只須要將第一個節點的next指針指向(n-1)結果的頭節點便可
代碼以下:
public ListNode createLinkedList(List<Integer> data) {ListNode firstNode = new Node(data.get( 0));// 將第一個節點的next指針指向n-1已經建立好鏈表的頭節點firstNode.next = createLinkedList(data.subList( 1, data.size()));return firstNode; // 返回頭節點}
此時咱們先通常
的步驟就完成了,看看是否是每次調用函數都縮小問題規模了,是否是問題規模每次都縮小1,都知足條件!接下來就是後特殊
了,劃重點:一行行查看此時的代碼,想一想每一行代碼在什麼狀況下出異常,一旦發現這就是特殊狀況了!
例如:上面函數中的第一行,若是data爲空的話,是否是就報錯了,那麼此時就須要作特殊狀況處理:
public ListNode createLinkedList(List<Integer> data) {if (data.isEmpty())return null;ListNode firstNode = new Node(data.get( 0));// 將第一個節點的next指針指向n-1已經建立好鏈表的頭節點firstNode.next = createLinkedList(data.subList( 1, data.size()));return firstNode; // 返回頭節點}
那麼到此爲止,咱們就完成了建立鏈表的遞歸程序編寫。不過癮?那咱們再來一個!
仍是老樣子,咱們先假設n-1個鏈表已經反轉完成了:
那麼此時咱們應該怎麼作呢?此時1這個元素的next指針仍是指向2的,由於後面的反轉並不會影響1元素的next指針:
因此此時咱們只須要將節點2的next設爲1,將節點1的next設爲null便可完成反轉!
代碼以下:
public ListNode ReverseList(ListNode head) {// 這裏獲得n-1反轉後鏈表的頭節點,也就是反轉前的最後一個節點ListNode newHead = ReverseList(head.next);// 將節點2的next設爲節點1head.next.next = head;// 將節點1的next設爲nullhead.next = null;return newHead;}
那麼此時先通常
就完成了,接下來就是尋找特殊(邊界)狀況了,一行行代碼看下來發現head和head.next爲null時會報異常,因而處理異常狀況:
public ListNode ReverseList(ListNode head) {if(head == null || head.next == null)return head;ListNode newHead = ReverseList(head.next);head.next.next = head;head.next = null;return newHead;}
到此爲止,反轉鏈表函數就已經完成,是否是感受按照數學概括法的思路寫遞歸仍是蠻清晰的呢!
數學概括法是遞歸的依據。
書寫遞歸的思路跟數學概括法的證實過程類似,不過須要注意的是,先書寫通常狀況,後根據通常狀況考慮特殊狀況;同時要牢記遞歸函數每次縮小規模程度必須爲「1」!
方法已經教給你了,接下去就是多練習了,趕忙找點題目練練手吧!