我有两个练习问题,我无法理解。对于#1,答案是列表是反向打印的,任何人都可以向我解释这个吗?另外#7,为什么列表一旦到达空值就会开始倒退?如果有人能提供一些快速解释,我们将不胜感激,谢谢!
void method1(Node<T> node) {
if(node == null)
return;
method1(node.getNext());
System.out.println(node.getData().toString());
}
一个。打印链表的节点。
湾以相反的顺序打印链表的节点。
℃。打印链表的备用节点。
d。以相反的顺序打印备用节点。
答案
湾以相反的顺序打印链表的节点。
void method1(Node<Integer> node) {
if (node == null)
return;
System.out.printf(“%d ”, node.getData());
if (node.getNext() != null)
method1(node.getNext().getNext());
System.out.printf(“%d ”, node.getData());
}
一个。 1 6 2 5 3 4
湾1 3 5 6 4 2
℃。 1 3 5 1 3 5
d。 1 3 5 5 3 1
答案
℃。 1 3 5 5 3 1
答案 0 :(得分:1)
问题1:
这是一个递归方法调用,这意味着它会一直调用自己,直到满足中断条件(在这种情况下,没有下一个节点要移动)。所以,让我们逐行了解这一点。
void method1(Node<T> node) {
if(node == null) // ends the recursive calls without doing anything extra
return;
method1(node.getNext()); // Do something with the next node before this node
System.out.println(node.getData().toString()); // Print contents of current node.
}
正如您所看到的,我们第一次实际打印任何内容都是在链接列表的末尾(当node.next()
返回null时)。在第一次打印之后,调用向上移动堆栈(因此向后移动到列表中),打印每个节点的内容。
问题2:
这与问题1几乎相同,只是引入了一些曲折。首先,我们在递归调用之后在和之前打印当前节点的内容。因此,实际上,我们将按顺序打印每个节点的内容,然后按相反的顺序打印。稍微令人困惑的部分是我们在每个节点上调用method1
,但在每个其他节点上,这意味着我们每次调用时都会跳过一个节点。
总结这个问题的答案,我们有效地打印当前节点的内容,跳过一个,打印下一个的内容等等......直到我们到达可用节点的末尾,然后我们只是回溯并再次打印所有内容(只是这次以相反的顺序)。
答案 1 :(得分:1)
如果您绘制调用堆栈,这些都更容易可视化。这些指令是按顺序执行的,所以我发现可视化调用序列和调用堆栈深度是有帮助的:
问题1:
List = 1 → 2 → 3 → 4 → 5 → 6
method1(1)
method1(2)
method1(3)
method1(4)
method1(5)
method1(6)
method(null)
return
println(6)
println(5)
println(4)
println(3)
println(2)
println(1)
此处的通话顺序可以从上到下看到。在打印任何内容之前调用method1
。一旦method1
命中基本案例,它就会返回上一次调用,在本例中是method1(6)
调用。
此处的每个缩进都是另一个recursive调用,有助于可视化call stack。有很多非常好的答案可以比我更好地解释递归(比如programmers.stackexchange.com上的这个。)
问题7:
你可以对这个问题做同样的事情:
1 → 2 → 3 → 4 → 5 → 6
method1(1)
printf("%f ", 1)
method1(3) // node.getNext().getNext() = 1 → 2 → 3
printf("%f ", 3)
method1(5)
printf("%f ", 5)
method1(null) // node.getNext().getNext() = 5 → 6
return
printf("%f ", 5)
printf("%f ", 3)
printf("%f ", 1)