反转一个单链表。如下示例::
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
一、 迭代法:
注意观察示例:1->2->3->4->5->NULL的反转可以看成:NULL<-1<-2<-3<-4<-5。
会发现链表的反转基本上就是箭头的方向的反转,即节点前驱和后继互换角色。
我们定义三个变量cur,pre和next分别表示当前节点,以及其前驱后继。cur初始化为head,其他初始化为NULL。
我们从头节点1开始遍历,1的next和pre原来分别是2和NULL(初始值)互换后1的next和pre变成NULL和2,依次这样遍历下去。
注意最后应该返回pre,不是cur。遍历结束后cur的值是NULL。
代码如下:
public ListNode reverseList(ListNode head){
ListNode pre = null, cur = head, next = null;
while(cur != null){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
方法2:头插法
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
//头插法 每次把cur.next那个节点放在头部
//m = 1, n = length的时候全部反转(直到cur.next为空)
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
for(int i = 1;i<m;i++) pre = pre.next;//pre是要反转部分的先序节点,相当于dummy
ListNode cur = pre.next;
for(int i = m;i<n;i++){
ListNode nxt = cur.next;
cur.next = cur.next.next;
//pre.next = nxt;
//nxt.next = cur; cur始终没变,这样写不行 会造成节点丢失
nxt.next = pre.next;
pre.next = nxt;
}
return dummy.next;
}
二、递归法:
递归法和迭代法思路是一样的。
代码如下:
public ListNode reverseList(ListNode head){
if(head == null || head.next == null){
return head;
}
ListNode n = reverseList(head.next);
head.next.next = head;//head.next是反转链表的末尾
head.next = null;
return n;
}
只是注意两个地方:
如果head是空或者遍历到最后节点的时候,应该返回head。
代码5,6行。节点替换的时候不要用n来代替head->next;因为对于递归来说它们不是等价的。但是head->next->next 等价于 n->next。