1. 程式人生 > >演算法入門題:如何反轉一個單向連結串列?

演算法入門題:如何反轉一個單向連結串列?

最近在 LeetCode 上面玩 ``連結串列`` 型別的題目,所以打算寫一篇文章,分享一下在做連結串列型別題目的心得。 眾所周知,玩連結串列就是玩指標,今天跟大家講解一個連結串列的入門題目,**如何反轉一個單向連結串列** 也是 LeetCode #206 是很熱門的一道程式設計題 [LC#206 Reverse Linked List](https://leetcode-cn.com/problems/reverse-linked-list/) ,如圖: ![vJapet](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/vJapet.png) ##### 解題理論: 想要反轉一個單向連結串列,除了當前的 head 指標外,我們還另外需要兩個輔助指標: * preNode 用於儲存上一個引用的指標 * nextNode 用於儲存下一個引用的指標 不管你使用什麼程式語言,反轉連結串列的公式都是一樣的,主要分為以下四步: 1. 將當前 head 引用的 next 引用傳遞給 nextNode 2. 將當前 preNode 引用賦值給 head.next 實現反轉(重要) 3. 移動 preNode 指標,準備進行下一次反轉 4. 移動 head 指標,準備進行下一次反轉 使用 Java 語言表示的程式碼如下: ```java public static ListNode reverseList(ListNode head) { ListNode next, pre = null; while (head != null) { next = head.next; head.next = pre; pre = head; head = next; } return pre; } ``` 因為動態語言允許交叉賦值,所以使用動態語言反轉連結串列就更加的簡單,程式碼如下: ```ruby def reverse_list(head) while(head != nil) cur_next, head.next, pre = head.next, pre, head head = cur_next end pre end ``` ##### 圖解資料結構 上面程式碼和文字描述看上去可能不太直觀,我們下面通過圖文的形式展示一個單向連結串列是如何被反轉的 單向連結串列的初始狀態: ![9Op3SJ](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/9Op3SJ.png) 然後我們第一步,開始初始化指標, ```java ListNode next, pre = null ``` 然後,執行第一步切換指引的程式碼: ```java next = head.next; ``` 這時候連結串列和指標的位置改變如下圖: ![MpVVX8](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/MpVVX8.png) 當執行第二步程式碼: ```java head.next = pre; ``` 這時候連結串列內的指標發生瞭如下的變化: ![yib8gf](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/yib8gf.png) 這裡可以看到 **head 引用的 next 指向已經發生的反轉變化** ,這一步也是反轉連結串列最重要的一步 後面第三步,第四步就是移動 preNode,head 指標,準備為下一次元素反轉做準備了 第三步程式碼: ```java pre = head; ``` 如圖: ![d2hXyW](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/d2hXyW.png) 這時候 preNode 已經跟 head 頭指標指向同一個節點,準備為下一次反轉做準備 第四步程式碼: ```java head = next; ``` 看到這裡大家發現 nextNode 指標其實作用不大,就是幫助 head 同學臨時佔一個位置的,反轉指標主要依靠 preNode 和 head,反轉完成後如何: ![2eIW9c](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/2eIW9c.png) 執行到這裡,元素 1 已經被反轉過來的,只需要將以上四步執行 N 次,就可以將一個長度為 N 的連結串列全部反轉,所以這套解法的時間複雜度就是 O(n),最後只要提交程式碼,你就能打敗全國 90%的對手,不信的話可以開啟 [LeetCode](https://leetcode-cn.com/problems/reverse-linked-list/submissions/) 提交一下程式碼 (●—●) ![5uTYuX](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/5uTYuX.png) ##### 總結 這道題非常簡單,如果你是老手的話就當幫你回顧一下反轉連結串列的解題思路,如果你是新手的話說不定能幫忙開啟演算法世界的大門,覺得文章不錯的話,可以分享給朋友,最後再留一個問題,可以思考一下: * 為什麼最終返回的指標是 preNode, 而不是 head ?