方法一
假设有下面这样一个单向链表
想要将其反转输出,即得到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;
}
}