单链表翻转也是面试中经常会被问到的一个经典算法。解决这个问题,最常想到的是递归,或者借助外部数组村组来实现。但是这两种方式的复杂度都偏高。
本文主要介绍使用指针来实现复杂度为O(1)的单链表翻转方法。
定义链表节点
首先定义链表节点1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42class Node {
    private int val;
    private Node next;
    public Node(int val) {
        this.val = val;
        this.next = null;
    }
    public Node(int val, Node next) {
        this.val = val;
        this.next = next;
    }
    public int getVal() {
        return val;
    }
    public void setVal(int val) {
        this.val = val;
    }
    public Node getNext() {
        return next;
    }
    public void setNext(Node next) {
        this.next = next;
    }
    public String print() {
        StringBuilder sb = new StringBuilder();
        if (next == null) {
            sb.append(val);
        } else {
            sb.append(val);
            sb.append("->");
            sb.append(next.print());
        }
        return sb.toString();
    }
}
递归法
反转当前节点之前先反转后续节点。这样从头结点开始,层层深入直到尾结点才开始反转指针域的指向。简单的说就是从尾结点开始,逆向反转各个结点的指针域指向。
| 1 | public Node recursion(Node head) { | 
三指针法
递归反转法是从后往前逆序反转指针域的指向,而三指针法是从前往后反转各个结点的指针域的指向。
基本思路是:将当前节点cur的下一个节点 cur.getNext()缓存到temp后,然后更改当前节点指针指向上一结点pre。也就是说在反转当前结点指针指向前,先把当前结点的指针域用tmp临时保存,以便下一次使用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public Node nonRecursion(Node head) {
       if (head == null || head.getNext() == null) {
           return head;
       }
       Node pre = head;
       Node cur = pre.getNext();
       Node next;
       while (cur != null) {
           next = cur.getNext();
           cur.setNext(pre);
           
           pre = cur;
           cur = next;
       }
       // 最后将原链表的头节点的指针域置为null,还回新链表的头结点,即原链表的尾结点
       head.setNext(null);
       return pre;
   }