鏈表的反轉(遞歸實現)

此處明確了實現的方法,另外非遞歸(迭代)的方法也可行。

首先我們需要知道一些基礎知識--即遞歸的相關概念。遞歸(Recursion)即函數自己調用自己,若問題可以使用遞歸來解決,則必須滿足以下三個條件:

1.可以要把解決的一個問題轉化爲一個新的問題,這個新問題的解決思路與原來相同,只是在有規律的變化(例如遞增遞減).

說明:遞歸可以解決的方法,非遞歸一定也可以.

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

  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章