leetcode-链表反转
https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/
对于链表反转其核心是通过将单链表原有的指针方向进行反转;
可以通过双指针,也可以通过递归两种方式实现反转
双指针
因此可以通过双指针迭代来实现,通过双指针每递进一次则执行一次反转操作,当迭代完成后,就完成了全部节点的指针方向反转;
对于每次方向反转重点在于通过 维护前一个指针指向的节点实现反转的操作,并通过维护下一个指针指向的节点实现遍历的操作;
/** * 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 : 示意图补充, 关于递归 入栈操作以及出栈操作时指针反转

浙公网安备 33010602011771号