1. 程式人生 > >Leetcode 206.反轉連結串列

Leetcode 206.反轉連結串列

反轉連結串列

反轉一個單鏈表。

示例:

輸入: 1->2->3->4->5->NULL

輸出: 5->4->3->2->1->NULL

 

 1 class Solution {
 2     public ListNode reverseList(ListNode head) {
 3         if(head==null || head.next==null){
 4             return head;
 5         }
 6         ListNode h = reverseList(head.next);
7 head.next.next = head; 8 head.next = null; 9 return h; 10 } 11 }

 

連結串列的翻轉是程式設計師面試中出現頻度最高的問題之一,常見的解決方法分為遞迴和迭代兩種。最近在複習的時候,發現網上的資料都只告訴了怎麼做,但是根本沒有好好介紹兩種方法的實現過程與原理。所以我覺得有必要好好的整理一篇博文,來幫忙大家一步步理解其中的實現細節。

  我們知道迭代是從前往後依次處理,直到迴圈到鏈尾;而遞迴恰恰相反,首先一直迭代到鏈尾也就是遞迴基判斷的準則,然後再逐層返回處理到開頭。總結來說,連結串列翻轉操作的順序對於迭代來說是從鏈頭往鏈尾,而對於遞迴是從鏈尾往鏈頭。下面我會用詳細的圖文來剖析其中實現的細節。

1、非遞迴(迭代)方式
  迭代的方式是從鏈頭開始處理,如下圖給定一個存放5個數的連結串列。

首先對於連結串列設定兩個指標:

然後依次將舊連結串列上每一項新增在新連結串列的後面,然後新連結串列的頭指標NewH移向新的連結串列頭,如下圖所示。此處需要注意,不可以上來立即將上圖中P->next直接指向NewH,這樣存放2的地址就會被丟棄,後續連結串列儲存的資料也隨之無法訪問。而是應該設定一個臨時指標tmp,先暫時指向P->next指向的地址空間,儲存原連結串列後續資料。然後再讓P->next指向NewH,最後P=tmp就可以取回原連結串列的資料了,所有迴圈訪問也可以繼續展開下去。

指標繼續向後移動,直到P指標指向NULL停止迭代。

最後一步:

2、非遞迴實現的程式

3、遞迴方式

  我們再來看看遞迴實現連結串列翻轉的實現,前面非遞迴方式是從前面數1開始往後依次處理,而遞迴方式則恰恰相反,它先迴圈找到最後面指向的數5,然後從5開始處理依次翻轉整個連結串列。

  首先指標H迭代到底如下圖所示,並且設定一個新的指標作為翻轉後的連結串列的頭。由於整個連結串列翻轉之後的頭就是最後一個數,所以整個過程NewH指標一直指向存放5的地址空間。

 

然後H指標逐層返回的時候依次做下圖的處理,將H指向的地址賦值給H->next->next指標,並且一定要記得讓H->next =NULL,也就是斷開現在指標的連結,否則新的連結串列形成了環,下一層H->next->next賦值的時候會覆蓋後續的值。

繼續返回操作:

上圖第一次如果沒有將存放4空間的next指標賦值指向NULL,第二次H->next->next=H,就會將存放5的地址空間覆蓋為3,這樣連結串列一切都大亂了。接著逐層返回下去,直到對存放1的地址空間處理。

返回到頭:

4、迭代實現的程式