Java 在链表的递归反转器中,对返回变量/值感到困惑

Java 在链表的递归反转器中,对返回变量/值感到困惑,java,recursion,linked-list,Java,Recursion,Linked List,前几天我问了一个类似的问题,但是当涉及到这个递归链表反向方法如何工作的细节时,我并没有真正得到我想要的答案 我有以下方法: public Node reverse(Node current) { if(current == null || current.next == null) { return current; } Node rest = reverse(current.next); current.next.next = curre

前几天我问了一个类似的问题,但是当涉及到这个递归链表反向方法如何工作的细节时,我并没有真正得到我想要的答案

我有以下方法:

public Node reverse(Node current)
{
    if(current == null || current.next == null)
    {
        return current;
    }
    Node rest = reverse(current.next);
    current.next.next = current;
    current.next = null;
    return rest;
}
如果在递归调用后修改
当前
变量,但返回
rest
,那么如何修改列表中的下一个链接?当我跟踪这个函数时,似乎
rest
被分解为它的最后一个元素,然后只返回最后一个元素

我看不出在递归调用之后修改
current
变量对返回值有什么影响

我已多次跟踪此函数,下面是一个示例:

假设
Node in=1
in.next=2

线索似乎如下:

reverse(in)(in当前为1,2)

从现在起,中的
现在被称为
当前的

rest=反向(current.next),相当于:
rest=反向(2)
通过基本大小写返回2

现在
rest=2

current.next.next=当前

这使得
当前=1,2,1,2

current.next=null
设置当前=1

函数返回的
rest等于2,没有
。下一个
值我可以看到,因为它在任何地方都没有被修改过,但是当我测试此
rest的输出时,它是2,1

那么,如何正确地交换rest呢

我觉得在我没有捕捉到的变量之间似乎存在某种引用,因为
rest没有声明

谁能帮我把这件事弄清楚吗


这看起来很简单,但到目前为止,它一直困扰着我。不过,此功能工作正常。似乎我的跟踪在告诉我如何操作方面效率很低。

无论递归调用返回了什么,都会原封不动地返回。递归调用返回了什么?链接列表中的最后一个节点

很自然,最后一个节点成为反向列表中的第一个节点

保存返回值后的最后几行处理将当前节点链接到反向列表的当前最后一个节点,这是您当前的下一个节点

重新链接完成后,您可以自由返回现在完全颠倒的列表的标题:

curr ->   next  ->  ....    -> last 
curr ->   next  ->  ... <- ... last
curr ->   <- next   ... <- ... last
. <- curr <- next   ... <- ... last
curr->next->最后

当前->下一步-> 返回递归调用返回的任何内容,保持不变。递归调用返回了什么?链接列表中的最后一个节点

很自然,最后一个节点成为反向列表中的第一个节点

保存返回值后的最后几行处理将当前节点链接到反向列表的当前最后一个节点,这是您当前的下一个节点

重新链接完成后,您可以自由返回现在完全颠倒的列表的标题:

curr ->   next  ->  ....    -> last 
curr ->   next  ->  ... <- ... last
curr ->   <- next   ... <- ... last
. <- curr <- next   ... <- ... last
curr->next->最后

当前->下一步-> 以您的示例为例,假设我们的列表有两个项目,12,其中1在开头,它们在开头有以下值:

1
值=1
下一个=2

2
值=2
Next=null

您可以调用
reverse(1)
,并在该上下文中(让我们通过递归深度和嵌套来标记它):

R1
电流=1
R2
电流=2
(返回2)
剩余=2
当前(1).下一个(2).下一个(赋值前为空)=当前(1)|现在2.下一个==1
当前(1).下一个(2)=null |因此现在1.下一个==null
(返回其余部分(即2))


现在,如果在1之前有另一个项目,当该项目被处理时,它会将1设置在其旁边,就像上面的示例中一样,1将2设置在其旁边。

以您的示例为例,假设我们的列表有2个项目,12,其中1位于头部,它们在开始时具有以下值:

1
值=1
下一个=2

2
值=2
Next=null

您可以调用
reverse(1)
,并在该上下文中(让我们通过递归深度和嵌套来标记它):

R1
电流=1
R2
电流=2
(返回2)
剩余=2
当前(1).下一个(2).下一个(赋值前为空)=当前(1)|现在2.下一个==1
当前(1).下一个(2)=null |因此现在1.下一个==null
(返回其余部分(即2))


现在,如果在1之前有另一个项,当该项被处理时,它会将1的值设置在其旁边,就像上面的示例中一样,1将2的值设置在其旁边。

这是有效的,因为变量是对对象的引用,而不是对当前对象的引用

举个例子(这不是为了遵守任何程序语言语法):

此时,
e1.next
e2.next
是对内存和
e3上存在的适当对象的接收。next
null
,在这种情况下不引用任何对象

我将说
x
y
,而不是
x
y
,以使解释更加简洁和简单。无论如何,变量都是指向对象的指针。我还使用了两个空格来缩进,这样线条就不会那么长

然后调用
reverse(e1)
,让我们打开递归,每行解释如下:

reverse(e1); // current points e1
{
  if(current == null || current.next == null) // false
  {
    return current; // not executed
  }
  Node rest = reverse(current.next); // recursion, here current points e2
  {
    if(current == null || current.next == null) // false
    {
      return current; // not executed
    }
    Node rest = reverse(current.next); // recursion, here current points e3
    {
      if(current == null || current.next == null) // true
      {
          return current; // returns current that points e3
      }
      current.next.next = current; // not executed
      current.next = null; // not executed
      return rest; // not executed
    } // end of recursion
    // now rest points e3 (the "if" above was true, returning current)
    // current is e2 again
    current.next.next = current; // e2.next.next (this is e3.next) = e2
    current.next = null; // e2.next points nothing
    return rest; // return e3 (rest points e3)
  } // end of recursion
  // now rest points e3
  // current points e1 again
  current.next.next = current; // e1.next.next (this is e2.next) = e1
  current.next = null; // e1.next points nothing
  return rest; // return a pointer to e3
}
因此,您得到了
e3
,以及
e3.next=e2
e2.next=e1
e1.next=null

请注意,递归的数量是obj的数量
reverse(e1); // current points e1
{
  if(current == null || current.next == null) // false
  {
    return current; // not executed
  }
  Node rest = reverse(current.next); // recursion, here current points e2
  {
    if(current == null || current.next == null) // false
    {
      return current; // not executed
    }
    Node rest = reverse(current.next); // recursion, here current points e3
    {
      if(current == null || current.next == null) // true
      {
          return current; // returns current that points e3
      }
      current.next.next = current; // not executed
      current.next = null; // not executed
      return rest; // not executed
    } // end of recursion
    // now rest points e3 (the "if" above was true, returning current)
    // current is e2 again
    current.next.next = current; // e2.next.next (this is e3.next) = e2
    current.next = null; // e2.next points nothing
    return rest; // return e3 (rest points e3)
  } // end of recursion
  // now rest points e3
  // current points e1 again
  current.next.next = current; // e1.next.next (this is e2.next) = e1
  current.next = null; // e1.next points nothing
  return rest; // return a pointer to e3
}