最近研究算法,遇到的一道頗有意思的問題——怎麼把一個鏈表反轉?
很容易想到一個方法:遍歷鏈表,數組做棧存儲路徑,元素逐個出棧獲得的就是反轉後的鏈表!查找資料發現,有更好的方式實現。java
仔細研究後,終於明白了其中的奧妙。小僧掌握了兩種方法,如下分別進行說明。node
首先給出鏈表結構:git
public class LinkedNode { Integer id ; LinkedNode next; public LinkedNode(Integer id) { this.id = id; } }
下一步構造出上圖的鏈表結構:github
LinkedNode node1 = new LinkedNode(1); LinkedNode node2 = new LinkedNode(2); LinkedNode node3 = new LinkedNode(3); LinkedNode node4 = new LinkedNode(4); node1.next = node2; node2.next = node3; node3.next = node4;
先給出代碼實現:算法
/** * 鏈表翻轉,循環 + 雙指針(pre、next)實現 * @param cur * @return */ public LinkedNode reverse(LinkedNode cur){ LinkedNode pre = null; while (cur!=null){ LinkedNode next = cur.next; // 1. cur.next = pre; // 2. pre = cur; // 3. cur = next; // 4. } return pre; }
循環體以前,鏈表示意圖:數組
以後進入while
循環,註釋標註的四個步驟會產生以下變化(圖中編號與註釋編號一一對應):this
第一次循環後,鏈表變成這樣:spa
以後的遍歷,鏈表的變化示意:指針
可見,while
循環執行完,pre
指向的節點,已是最新的頭節點了!code
遞歸的實現方式,彷佛更容易理解。
/** * 鏈表反轉,遞歸實現 * @param node * @return */ public LinkedNode reverse2(LinkedNode node){ if(node.next==null){ return node; } LinkedNode newHead = reverse2(node.next); node.next.next = node; //node.next.next 換成 newHead.next 不行,由於node在遞歸中在追溯上一個節點,仔細體會下 node.next = null; return newHead; }
首先會經過遞歸調用找到尾節點,以後作了兩件事:
node.next.next = node;
)node.next = null;
)rentun newHead
後,回溯到節點2(此時node就是節點2),再次重複以前的兩件事——節點反指和當前節點指向null節點。
再次回溯,獲得最終的結果。
老規矩,完整代碼見git:暗夜君王的demo練習——鏈表反轉
Done !