问题描述
每行都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 head
在 if
语句之后确实被执行了。
在你的函数体中,我们几乎立即递归调用它,所以它就像爬梯子,执行函数的第一部分:
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.next
和 head.next
指向完全相同的对象。
请记住,我们现在处于 Head 4,所以 newHead
与 head.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.next
,Head 4
会将 head.next.next
放在 Head 3
属性中,这就是我们所需要的。
所以在下降的过程中,Head 4.next
变成 Head 4
,Head 5.next
变成 Head 3
等等。
递归函数很难直观地掌握,所以我建议从简单的开始,例如:Recursion in JavaScript Explained Using a freeCodeCamp Challenge。