假设我有一个名为Node的类:
public class Node {
public Node next;
//etc......
}
和一个类NodesList:
public class NodesList {
public Node head;
//etc....
}
现在我想实现一个反转列表的函数,如:
public reverseList () {
Node curr = head;
Node prev = null;
while (curr != null){
curr.next = prev;
prev = curr;
head = head.next;
curr = head;
}
head = prev;
}
我的问题非常基本:我分配了 curr = head 。
为什么,在作业 curr.next = prev, 中,它不会将头更改为 head.next = prev 并破坏列表?
我在哪里可以阅读它以了解更多幕后发生的事情?
非常感谢!!!
答案 0 :(得分:4)
curr
和head
最初指向第一个节点。当您执行curr.next = prev
时,curr.next
和head.next
都是null
。由于第一个节点与列表其余部分之间的连接丢失,因此您无法立即反转列表。现在,当head = head.next
语句执行时,您的head
将指向null
,这意味着列表没有起始点。
要记住的一件事是永远不要使用head
指针移动列表中的节点。应该head
始终指向列表的开头。在反转列表的情况下,可以更新head
以在反转后指向列表的新起始节点。
反转列表的一种方法是:
Node prev = null;
Node curr = head;
Node next;
while (curr != NULL)
{
next = curr.next;
curr.next = prev;
prev = current;
current = next;
}
head = prev;
在上面的代码片段中,有一个名为next
的指针,它首先指向current
的下一个节点。所以现在执行curr.next = prev
之后,curr可以通过语句curr = next
移动到列表中的下一个节点。这可确保列表的连接不会丢失。
while循环反转列表后,prev
将指向列表的新第一个节点。现在,您可以修改head
以指向此节点。
答案 1 :(得分:0)
为什么在作业
curr.next = prev
中,它还没有将head
更改为head.next = prev
并破坏列表?
但确实将head.next
更改为prev
。在赋值时,curr
和head
是对同一对象的引用。这不会破坏列表,因为head
在循环运行时被设置为其他元素。
如果这听起来有点令人困惑,请继续阅读。
我在哪里可以阅读它以了解更多幕后发生的事情?
幕后没有任何事情发生,你只需要在场景之前正确看待发生的事情"。
发生的事情是您正在使用旧列表的相同节点构建反向列表。现在,你正在以唯一的方式遍历旧列表,这是前进的 - 从旧列表的头部到尾部,通过.next
前进。但是对于新列表,这需要是列表的末尾,所以每当你看到另一个元素时,你在头之前添加它而不是在尾之后添加 >你的建设清单。
所以如果你有:
(head) -> [node 1] -> [node 2] -> [node 3]
您正在将其转换为:
null <- [node 1] <- (head) [node 2] -> [node 3] -> null
null <- [node 1] <- [node 2] <- (head) [node 3] -> null
null <- [node 1] <- [node 2] <- [node 3] <- (head)
答案 2 :(得分:0)
不是推理什么指向什么,而是推理弹出和推送操作要简单得多。在伪代码中,您可以将lst
反转到rvs
,如下所示:
rvs = null;
while (lst != null) {
Node tmp = pop(lst);
rvs = push(rvs, tmp);
}
// rvs now contains the reversed list
现在我们需要做的就是将pop
和push
替换为其实现:
rvs = null;
while (lst != null) {
// pop from lst
Node tmp = lst;
lst = lst.next;
// push onto rvs
tmp.next = rvs;
rvs = tmp;
}