反转链表的递归解法与非递归解法

207 阅读2分钟

反转链表

1. 非递归解法:

解题思路:

  • 定义三个指针: cur , p1 p2, cur与p1为了完成指针逆指, p2保存下一个应当逆转的节点,防止迷路
  • 每次让 p1 的next 指向 cur,实现一次局部反转
  • 局部反转完成之后,cur p1和 p2 同时往前移动一个位置
  • 循环上述过程,直至 p1到达链表尾部

思路图解:

代码实现:

var reverseList = function(head) {
    if(!head) return null
    let cur = null
    let p1 = head
    let p2 = head.next
    while(p1) {
        p1.next = cur
        cur = p1
        p1 = p2
        p2 = p2 ? p2.next : null
    }
    return cur
};
2. 递归解法:

递归解法可能有点绕,这里进行详尽说明

解题思路:

终止条件就是链表为空,或者是链表没有尾结点的时候,直接返回

if (head == null || head.next == null)
    return head;

递归调用是要从当前节点的下一个结点开始递归。逻辑处理这块是要把当前节点挂到递归之后的链表的末尾

代码实现:

function  reverseList(head) {
    //终止条件
    if (head == null || head.next == null)
        return head;
    //保存当前节点的下一个结点
   let next = head.next;
    //从当前节点的下一个结点开始递归调用
    let reverse = reverseList(next);
    //reverse是反转之后的链表,因为函数reverseList
    // 表示的是对链表的反转,所以反转完之后next肯定
    // 是链表reverse的尾结点,然后我们再把当前节点
    //head挂到next节点的后面就完成了链表的反转。
    next.next = head;
    //这里head相当于变成了尾结点,尾结点都是为空的,
    //否则会构成环
    head.next = null;
    return reverse;
}

因为递归调用之后head.next节点就会成为reverse节点的尾结点,我们可以直接让head.next.next = head;这样代码会更简洁一些,看下代码

function reverseList(head) {
    if (head == null || head.next == null)
        return head;
    let reverse = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return reverse;
}