此處明確了實現的方法,另外非遞歸(迭代)的方法也可行。
首先我們需要知道一些基礎知識--即遞歸的相關概念。遞歸(Recursion)即函數自己調用自己,若問題可以使用遞歸來解決,則必須滿足以下三個條件:
說明:遞歸可以解決的方法,非遞歸一定也可以.
2.可以應用這個轉化過程使問題得到解決。
說明:使用其他方法(非遞歸的)一定存在同樣可以解決問題的方法,但效率可能不如遞歸
3.必須要有一個明確的結束遞歸的條件。
說明:該條件是我們一開始就知道或者說設置好的,作爲過程的出口。
遞歸的核心:逐級調用,逐級返回
說明:
1.當函數自己調用自己時,系統將自動把函數當前的變量和形參暫時保留起來,在新一輪的調用過程中,系統爲新調用的函數所用到的變量和形參開闢另外的存儲單元(即內存空間),每次調用函數所使用的變量在不同的內存空間中。
2.遞歸調用的層次越多,同名變量(因爲就是函數自身)佔用的存儲單元也就越多。每次函數的調用,系統都會爲該函數的變量開闢新的內存空間。
3.當本次調用的函數運行結束時,系統將釋放本次調用時所佔用的內存空間。程序的流程返回到上一層的調用點,同時期的當初進入該層時,函數的變量和形參所佔用的內存空間的數據(這點很重要,它使我們的結果在不斷的變化中,直到遇到出口)
下面是關於鏈表反轉實現的思路
與迭代不同的是,遞歸是從後向前,即從尾節點向頭節點逐個翻轉來實現效果的。
首先我們假定創建了一個共有5個節點的鏈表,像下邊這樣:
之後我們建立一個新的變量NewH,並同時移動H直到它們指向尾節點,此時NewH作爲新的頭節點,其指向固定在此位置
然後H指針逐層返回的時候做下圖的處理,將H的指向的地址賦值給H->next->next指針,並一定注意要讓H->next=NULL
說明:此處爲操作的核心,實現了斷鏈和反轉其指向的功能。由遞歸的相關概念我們可以知道,逐級返回的一開始,head就指向前一個節點了(即'4'這個節點),而head->next->next與head的基準是不一樣的!前一個在此時指的是'5'這個節點,因此其next的next,即null的next,本來是指向未開闢的(無法輸出)內存,但此時我們將它改爲指向前一個節點,實現了反轉的效果,並在此操作後將'4'這個節點斷開(即指向NULL)
繼續上述操作:
直到返回到頭:
部分代碼如下:
ListNode* reverse(ListNode* H) {
//包括特殊情況
if (H == NULL || H->next == NULL)
return H;
ListNode *newH = reverse(H->next);//注意,此處的操作是一直循環到鏈表末尾
H->next->next = H;//反轉每個節點的指向
H->next = NULL;
return newH;
}
參考資料:
1.https://blog.csdn.net/fx677588/article/details/72357389
2.http://www.jb51.net/article/39918.htm