1. 单链表反转
class ListNode<T>{
T val;
ListNode next;
ListNode(T val){
this.val = val;
}
}
迭代方式
public ListNode reverseByIteration(ListNode head){
ListNode prev = null;
while(head != null){
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
下面来举例看一下算法运行方式:
反转:1->2->3->4->null
第一次迭代:
next = 2->3->4->null //next是一个临时指针,保存后续的链表
head(1) -> prev(null) //操作head指针指向prev
prev(1) -> null //将prev指针指向head
head = 2->3->4->null //将head指向剩下的链表
第二次迭代:
next = 3->4->null
head(2) -> prev(1) -> null
prev(2) -> 1 -> null
head = 3->4->null
第三次迭代:
next = 4->null
head(3) -> prev(2) -> 1 -> null
prev(3) -> 2 -> 1 -> null
head = 4->null
第四次迭代:
next = null
head(4) -> prev(3) -> 2 -> 1 -> null
prev(4) -> 3 -> 2 -> 1 -> null
head = null
结束迭代,返回prev指针
这个算法的关键在于三个指针:
next:每次循环都会新建一个,为head保存后续链表
head:首先指向prev,为prev保存新链表的表首,待prev接管后,指向next保存的旧链表
prev : 保存新链表的表首(像个气泡,一旦被head压住就会拼命浮到最上面)
递归方式
public ListNode reverseByRecursive(ListNode head){
if (head == null || head.next == null){
return head;
}
ListNode next = head.next;
ListNode newHead = reverseByRecursive(next);
next.next = head;
head.next = null;
return newHead;
}
这个算法就用一张手画图来分析吧
首先要知道,递归是个栈。
这个算法一路将链表递归下去,直到最后一个元素4,而4又恰好是反转链表的第一个节点,因此将newHead指针一路往递归栈底传递。
这个算法关键的两步是
next.next = head;
head.next = null;
next指针在调用递归后已经从原先的指向首元素,变为指向末元素。举个例子来说: 原先next(3) -> 4 -> null, 调用reverseByRecursive后,为newHead(4) -> next(3) -> null。而head是传递来的参数,next(3)的上一层是2。所以会变成newHead(4) -> next(3) -> head(2) -> 3 -> 4 -> null。最后head.next = null的用意就是清掉后面那些东西。最后return 的newHead(4) -> next(3) -> head(2) -> null。
这个算法的关键也在于三个指针:
newHead:反转链表的表首,一路传递就行
head:这是个临时指针,依次指向4->3->2->1
next : 反转前作为参数,反转后作为链表尾添加新节点。