考虑这一点的一种方法是举一个小例子。首先,两种边缘情况:
- 如果列表为空,则它已经被反转(很简单)
- if
curr
是单个节点,它是它自己的反转(再次,微不足道);因此将当前列表头设置为curr
.
假设这些都不成立,那么棘手的事情是弄清楚最后一段代码是如何工作的。想必整个过程都是通过调用来启动的reverse(head)
。让我们看看二元素列表会发生什么:
head = curr(0)
|
V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
由于每个递归调用都会创建一个新的curr
,因此我curr
使用索引进行了注释以显示适用的递归级别。现在有一个调用reverse(curr.next)
。在该调用期间,方法开始处的图片如下所示:
head curr(1)
| |
V V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
这满足了第二种边缘情况,因此该方法将图片更改为:
head = curr(1)
|
V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
(请注意,虽然curr
它是一个单元素列表,但该元素不是head
。这就是整个事情起作用的关键!)现在方法返回,我们又回到了第一次调用。图片现在看起来像这样:
curr(0) head
| |
V V
+---+ +---+
| 0 |->| 1 |->null
+---+ +---+
第二行代码(在第三块中)是curr.next.next = curr;
. 这会将图片更改为:
curr(0) head
| |
V V
+---+ +---+
| 0 |->| 1 |--\
+---+ +---+ |
^ |
| |
\-----------/
最后,它设置curr.next = null;
:
curr(0) head
| |
V V
+---+ +---+
| 0 |->null | 1 |--\
+---+ +---+ |
^ |
| |
\------------------/
稍微盯着看应该会让你相信这个列表实际上是颠倒的。
可以使用相同的技术来查看这如何反转更长的列表。考虑它的最简单方法是调用reverse(curr.next)
将反转列表的尾部,接下来的两行将附加curr
到列表的末尾。