需要对 javascript 中的递归反向单链表代码进行解释

问题描述

每行都console.log,看过很多 YouTube 视频,但无法理解。 我需要一步一步地了解正在发生的事情。

举个例子,我知道在 if 语句之后的 return head 永远不会被调用,但它应该考虑到每次 newHead 被声明时它都会调用 head.next 作为新的前往 reverseList(head),这应该导致 head.next === null

下面是我的代码

let headList = {
  value: 1,next: {
    value:2,next: {
      value:3,next: {
        value:4,next: {
          value:5,next: null
        }
      }
    }
  }
}

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

    newHead = reverseList(head.next);

    head.next.next = head;
    
    head.next = null;
    return newHead;

};

reverseList(headList)

解决方法

return headif 语句之后确实被执行了。

在你的函数体中,我们几乎立即递归调用它,所以它就像爬梯子,执行函数的第一部分:

    if(head == null || head.next == null) {
        return head
    }

    newHead = reverseList(head.next);```

对于我们每个人:

Head 1 ↩
  Head 2 ↩
    Head 3 ↩
      Head 4 ↩

现在我们在 Head 4 处,再次递归调用参数为 { value: 5,next: null } 的函数,但这是我们最后一次执行递归,因为我们达到了函数的基本情况 - 函数参数满足 {{1} } 语句,它立即返回到 if

现在我们将爬回这个调用堆栈,并在向下的过程中为每个磁头执行函数的第二部分。

Head 4

现在冻结时间,当我们在 // newHead = reverseList(head.next); <-- Resuming from here on the way back head.next.next = head; head.next = null; return newHead; 时,准备爬下调用堆栈!

由于我们将 Head 4 作为参数传递给最后一个递归函数调用并使其原样返回,因此 head.nexthead.next 指向完全相同的对象。

请记住,我们现在处于 Head 4,所以 newHeadhead.next.next = head 相同。这意味着 newHead.next = head 现在在 Head 4 之后!函数返回 Head 5

让我们继续执行,现在我们在 Head 3。

我们需要写 { value: 5,next: { value: 4,next: null }} 而不是 head.next.next 的原因是因为在调用堆栈向下的过程中我们需要将 newHead.next 对象附加到 Head 3 属性而不是Head 4.next(因为 newHead.next 已经指向 newHead.next)。

Head 4 就像在说‘当我们开始执行函数时,我想站在我面前的脑袋前面。

由于 head.next.next 引用 Head 3.nextHead 4 会将 head.next.next 放在 Head 3 属性中,这就是我们所需要的。

所以在下降的过程中,Head 4.next 变成 Head 4Head 5.next 变成 Head 3 等等。

递归函数很难直观地掌握,所以我建议从简单的开始,例如:Recursion in JavaScript Explained Using a freeCodeCamp Challenge