对于链表反转其核心是通过将单链表原有的指针方向进行反转;

可以通过双指针,也可以通过递归两种方式实现反转

双指针

 

因此可以通过双指针迭代来实现,通过双指针每递进一次则执行一次反转操作,当迭代完成后,就完成了全部节点的指针方向反转;

对于每次方向反转重点在于通过 维护前一个指针指向的节点实现反转的操作,并通过维护下一个指针指向的节点实现遍历的操作;

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
       ListNode first = null;
       ListNode second = head;
       while(second != null){
           // 记录当前存在原始关联关系的节点
           ListNode temp = second.next;
           // 将当前second指针指向的节点的next指针指向前一个指针first
           second.next = first;
           //将first指针往后移动一位
           first = second;
           //将second 指针往后移动一位
           second = temp;
       }
       // 当执行到这里说明当前链表已遍历结束
       return first;
    }
}

其具体的步骤为

1: first = null; second = head;初始化维护 first 和 second 两个指针

2:temp = second.next; 将second 节点指向的next节点数据使用临时变量进行缓存

3:second.next = first; 将原有的 second.next 指向当前second的前一个节点first

4:first = second; second = temp;同时将first和second 进行后移一位,对于first之前的节点指向方向已完全反转,对于second之后的节点代表的是等待反转的原数据;

5:并直到second 指向为null 就表示当前链表遍历结束,且指针方向反转也已结束;

 

递归

递归实际是利用到了 栈的特性,先进后出,通过先压栈,再出栈操作实现链表从尾到头的遍历操作

 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        // 继续递归遍历链表
        ListNode ret = reverseList(head.next);
        // 当执行到该处时说明此时的ret节点为最后一个节点,而head为ret前一个节点
        // 此时需要从最后一个节点位置开始执行指针反转操作
        // 当前操作目的 为 head.next 表示当前head节点的next节点; head.next.next = head,表示将当前head.next节点的next指针指向当前head节点; 
        head.next.next = head;
        // 断开原有的head.next指针指向关系
        head.next = null;
        // 这里不能直接使用 ret.next修改的原因为,对于使用递归操作时压入栈中的是head节点
        // 对于递归真正的执行过程实际就是出栈的过程,实际就是链表反向遍历的过程
        // 对于每一次出栈过程实际就是head 及其 next节点 关联关系反转的过程
        // 利用栈实际上就是间接维护了head->prev 的关系,对于出栈实际就是 head = head->prev
        // 关于递归实际就是维护了一个head指针,通过压栈操作顺序遍历,通过出栈操作实现反向遍历
        return ret;
    }
}

对于递归中的ret 变量只需要将其当做结果变量即可,真正作为指针移动的实际是head

通过出栈操作间接实现了前指针的虚拟关系(head->prev 实际就是当前在栈中存储下一个出栈节点)

 

//TODO : 示意图补充, 关于递归 入栈操作以及出栈操作时指针反转