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

需要解释javascript中的递归反向单链表代码吗,javascript,reverse,singly-linked-list,recursive-datastructures,Javascript,Reverse,Singly Linked List,Recursive Datastructures,我浏览了console.log的每一行,看了很多youtube视频,但我无法理解它。 我需要一步一步地了解正在发生的事情 举个例子,我知道if语句之后的return head从未被调用,但它应该考虑到每次声明newHead时,它都会调用head.next作为reverselishead中的新head,这将导致head.next==null 下面是我的代码: let headList = { value: 1, next: { value:2, next: {

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

举个例子,我知道if语句之后的return head从未被调用,但它应该考虑到每次声明newHead时,它都会调用head.next作为reverselishead中的新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)
在if语句实际执行后返回head

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

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

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

对于我们每个人来说:

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

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

 // newHead = reverseList(head.next); <-- Resuming from here on the way back

    head.next.next = head;
    
    head.next = null;
    return newHead;
现在冻结时间,我们在头4,准备爬下调用堆栈

由于我们将head.next作为参数传递给最后一个递归函数调用,并将其原封不动地返回,因此head.next和newHead指向完全相同的对象

记住,我们现在在头4中,所以Head.next.next=头与newHead.next=头相同。这意味着现在头4在头5之后!函数返回{value:5,next:{value:4,next:null}

让我们继续执行,现在我们在头3

我们需要编写head.next.next而不是newHead.next的原因是,在调用堆栈中,我们需要将head 3对象附加到head 4.next属性,而不是newHead.next,因为newHead.next已经指向head 4

next.next就像说‘我想站在我们开始执行函数时就在我前面的头的前面’

由于head3.next引用head4,Head.next.next将把head3放在head4.next属性中,这就是我们所需要的

所以在下降的过程中,头4变成头5。下一步,头3变成头4。下一步等等


递归函数可能很难直观地理解,因此我建议从更简单的函数开始,例如:。

如果要检查实际的头部,在递归调用开始后,您将永远无法到达该部分。设置断点并遍历代码。感谢您的详细解释!但有一部分我不明白。当头第一次返回时,它返回分配给newHead的当前头{value:5,next:null}。我得到newHead传递的最后一个值是`{value:4,next:{value:5,next:null}},但是最后一个返回头`应该使其成为value:4上次传递给reverseList函数的参数是{value:5,next:null}。否则,若条件和函数将进一步递归,它将不满足。想象一下,我们正处于最后一次调用reverseList的时刻,这是我的插图中的头4。我们的头是{value:4,next:{value:5,next:null}。因此,我们最后一次使用head.next作为参数调用reverseList,这使得它{value:5,next:null}。确切地说,上次调用newHead=reverseListhead.next时,head={value:4,next:{value:5,next:null},现在reverseList中的新head是{value:5,next:null},但是返回的head应该赋值{value:5,next:null}到newHead,不仅如此,而且因为reverseList上次接收到`{value:5,next:null}`作为head,其余代码的新head应该是`{value:5,next:null}`,这是我没有得到的部分。感谢您花时间回答我们在返回的过程中更改newHead的内容,使用以下行:head.next.next=head。请记住,在向上的过程中,head.next引用的是更高的一个head,例如head 3.next是head 4。它在返回的过程中仍然引用同一个对象,并且通过修改head.next对象,我们可以找到它直接修改newHead对象,因为head.next现在位于newHead内部。如果您难以理解head.next.next是如何修改newHead的,请尝试阅读以下内容: