在Java中反转LinkedList

时间:2010-10-30 16:47:32

标签: java collections

我正在查看此帖Reversing a linked list in Java, recursively

中的解决方案

我复制了下面的解决方案之一。我实现了它,它工作正常。

public ListNode Reverse(ListNode list)
{
    if (list == null) return null; // first question

    if (list.next == null) return list; // second question

    // third question - in Lisp this is easy, but we don't have cons
    // so we grab the second element (which will be the last after we reverse it)

    ListNode secondElem = list.next;

    // bug fix - need to unlink list from the rest or you will get a cycle
    list.next = null;

    // then we reverse everything from the second element on
    ListNode reverseRest = Reverse(secondElem);

    // then we join the two lists
    secondElem.Next = list;

    return reverseRest;
}

然而,我不明白的是最后几行。

secondElem.next = list;
return reverseRest;

看来我们根本没有回到第二个电影?但我通过代码调试,看起来secondElem已经在reverseRest内。这是因为它是Java中的值引用,并且在应用secondElem.Next=list时会自动更新吗?

3 个答案:

答案 0 :(得分:5)

不要考虑传递语义,考虑内存中的对象和包含对它们的引用的变量。

初始状态:

(list)
   |
   V
[  1  ] -> [  2  ] -> ... -> [  N  ]

list.next = null;后:

(list)   (secondElem)
   |          |
   V          V
[  1  ]    [  2  ] -> ... -> [  N  ]

递归致电:

(list)   (secondElem)      (reverseRest)
   |          |                 |
   V          V                 V
[  1  ]    [  2  ] <- ... <- [  N  ]

secondElem.Next = list;之后的最终状态:

(list)   (secondElem)      (reverseRest)
   |          |                 |
   V          V                 V
[  1  ] <- [  2  ] <- ... <- [  N  ]

答案 1 :(得分:4)

如果您的目标是简单地撤消列表,请使用Collections.reverse(list)

答案 2 :(得分:0)

  

然而,我不明白的是最后几行。

     

secondElem.next = list;
  return reverseRest;

让我向您解释一下您不理解的两行:

1.secondElem.next = list;

我认为secondElem的创建引入了额外的复杂性。根本不需要变量secondElem。

而不是:

    // then we reverse everything from the second element on
    ListNode reverseRest = Reverse(secondElem);

    // then we join the two lists
    secondElem.Next = list;

使用此:

ListNode reverseRest = Reverse(list.next);    
list.next.next = list;

更容易掌握。最后一行代码清楚地显示了列表反转过程本身!

2. return reverseRest;

查看reverseRest变量&amp;的用法了解它的目的。它的唯一目的是将列表原始尾部的值渗透到所有递归调用的末尾,这样我们就可以将原始尾部(也就是新的头部)返回给调用Reverse函数的main函数。你必须通过理解我们在递归调用之间根本不改变变量reverseRest的值来快速得到这个 - 无论我们从Reverse(secondElem)返回的值是什么,我们都返回它“就像它来自函数!” / p>