我正在查看此帖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
时会自动更新吗?
答案 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>