方法一
假設有下面這樣一個單向鏈表
想要將其反轉輸出,即得到4->3->2->1這樣一個鏈表,我首先想到的是從拿到最後一個節點前面一個節點將他刪除接在最後一個節點的後面依次下去不就可以了麼
但是這樣就需要五個指針:
- head指針記錄開始位置。
- mark指針記錄原本的尾節點位置,因爲當有節點接在原本尾節點之後就無法用
next=null
來找到原本的尾節點。 - pre指針記錄mark的前一個節點,用於刪除和重新拼接
- beforePre指針記錄pre的前一個節點,要將他指向最後一個節點,用於下一次遍歷
- 新的尾節點
但是這樣是不是太麻煩了呢?五個指針記錄,每次找到原尾節點的前一個值就需要一次遍歷鏈表
方法二
如何只用遍歷一次就可以完成呢?先將前兩個反轉
這樣的關鍵就在於記錄頭指針(不是head,而是p,因爲head第一次反轉之後它就不在第一個了),保存head的下一個節點信息,因爲要將head接在下下一個節點上(就像刪除一樣),所以需要一個臨時節點(next)保存head.next的信息。
代碼
public class Solution {
public Node ReverseList(ListNode head) {
if(head.head==null){
return null;
}
/*ListNode是一個封裝鏈表,而不是節點所以要將他的head取出來*/
Node headNode = head.head;
Node p = new Node();
p.next=headNode;
while (headNode.next!=null){
/*將當前節點的下一個節點保存下來*/
Node next = headNode.next;
/*刪除下一個節點p -> 1 -> 3-> 4->5*/
headNode.next = next.next;
/*將要反轉的的節點反轉p -> 2 -> 1 -> 3-> 4->5*/
next.next=p.next;
p.next = next;
}
return p;
}
}
然後我發現牛客網測試通不過,因爲他給的Node結構如下
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
他的node不允許創建空節點,因此不能直接添加在p後面,因爲他是頭節點,而要直接改變p的值就需要一個臨時節點將頭節點信息保存下來
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode p = head;
if(head==null){
return null;
}
while (head.next!=null){
/*將當前節點的下一個節點保存下來*/
ListNode next = head.next;
/* p */
/* | */
/*刪除下一個節點 1 -> 3-> 4->5 */
/* | */
/* head */
head.next = next.next;
/* p */
/* | */
/*反轉節點 2 -> 1 -> 3-> 4->5 */
/* | */
/* head */
/*因爲p節點是真正的頭節點會不斷改變,因此臨時節點temp保存之前的信息*/
ListNode temp = p;
p = next;
/*完成鏈表鏈接*/
p.next = temp;
}
return p;
}
}