所以我正在浏览 Cracking the Coding Interview 来浏览一些采访内容并且我遇到了这个链接列表实现,也许它已经有一段时间了,但它完全超出我的想象。我理解其中的大部分,除了一条特定的线,它让我失望。我将在下面发布代码(供参考,本书没有提到语言,但它似乎是Java。)
class Node {
Node next = null;
int data;
public Node(int d) {
data = d;
}
void appendToTail(int d) {
Node end = new Node(d);
Node n = this;
while(n.next != null) {
n = n.next;
}
n.next = end;
}
}
我对这一行感到有些困惑:Node n = this
- 我不确定this
指的是什么,除非是在谈论next
- 为什么不把它设置为在那种情况下null
?
答案 0 :(得分:2)
这是Java。
“this
”指的是进行调用的类的特定实例。在这种情况下,“this
”是指您正在处理的特定类Node
。变量“end
”创建 new 和使用传递的int“Node
”构造的d
类的单独版本。
答案 1 :(得分:2)
this
指的是类对象的特定实例。由于构造了对象,因此可以有多个类实例,但使用this
关键字可以获得对自身的引用,这意味着对正在调用其方法的对象的特定实例的引用。
链表是一组节点,它们很好地链接在一起。当您调用appendToTail()
时,节点将查看链接到自身的所有Node对象并跟随链。为了获得对自身的引用以遵循其自己的链,使用this
关键字。
您还要问为什么null
在这种情况下不会用来初始化n
。在循环约束中首次调用NullPointerException
时,这将导致n.next
,因此将其自己的引用用作链接列表迭代的起始点。
这个(双关语)起初可能是一个令人困惑的话题,但让我们使用你提供的例子。
Node n = this;
while(n.next != null) {
n = n.next;
}
假设我们列表中当前链接了4个对象,为简单起见,正在调用appendToTail()
的Node对象是列表的头部。这是来自上述代码段的每个循环迭代中节点n的参考值。
this
this.next
this.next.next
this.next.next.next
循环当前结束n = this.next.next.next
的引用。然后,我们将n
的下一个值(其中n
当前指向链接链的末尾)设置为我们在方法开头创建的新对象,这使得它成为列表的新结尾。 (n.next = end
现在相当于this.next.next.next.next = end
)。
半不必要的编辑:这是用Java来解释的。在我写完这个答案后,似乎有人添加了C ++标签
答案 2 :(得分:0)
由于这是一个链接列表,所有节点都已连接,并且您有一个启动节点(根)。所以当使用它时,它看起来像这样:
Node root = new Node(6); //need an instance first
root.appendToTail(5);
root.appendToTail(3);
//6->5->3
由于节点已连接,我需要一个启动节点,需要检查是否有下一个节点,我需要更深入地搜索。当节点没有下一个节点时,它是当前最后一个节点并且可以添加我的新节点。所以这在Java中引用了类的当前实例。在我的示例中, root 节点(因为我称之为root.appendToTail)。因此,该方法将从根节点(值6)搜索下一个节点而没有下一个节点(值为3的节点)并将其附加到那里。如果我可以获得子引用并调用child3.appendToTail,则该方法将从child3搜索而不是从我的根开始。
如果将 n 设置为null并从 this.next 重写while,那么当您使用appendToTail的当前节点没有下一个节点时,您会遇到问题并抛出NullPointerException。
答案 3 :(得分:0)
Node n = this;
表示对正在调用此方法的对象的n个对象引用。
因此,方法循环到下一个对象,直到下一个对象为空并将end
节点分配给结尾。
让我们看看
1 -- 2 -- 3 -- 4
*
|
*
obj
你有一个指向节点1的obj
对象。当你打电话给obj.appendToTail(5)
时
Node end = new Node(d); //new node is created to add to the end.
Node n = this; //local n object is referenced to node 1(or obj)
while(n.next != null) {
n = n.next;
}
//n here is node 4 since there is no next node to 4
n.next = end; //node 5 is tail now
最终结果:
1 -- 2 -- 3 -- 4 -- 5
答案 4 :(得分:0)
任何Node实例都可以调用appendToTail()
。
注意事实上,这里实际上Node
不将自己附加到列表的尾部,这里发生的是新节点被创建并添加到尾部,而不是在其上方法被调用。
要实现这一点,首先我们需要在给定当前Node
的情况下找到列表的尾部。
// n is pointing to current Node
while(n.next != null) {
n = n.next;
}
一旦我们找到了具有next == null的节点,这就是列表的尾部,所以我们现在可以将新的Node
添加到尾部:
// n points to current tail before next line is invoked
n.next = end;
至于为什么有行:
Node n = this;
因为没有LinkedList
类来维护对头部的引用,所以你必须能够从任何给定的节点进行迭代。这就是这里发生的事情,你从调用了appendToTail
的Node开始迭代,但是从头到尾,该Node可以是任何东西。
作为旁注,如果您手动实现链接列表,请确保实际上具有类LinkedList,它将提供add
,get
,size
,{{1}等方法等等,而不是把它们放到Node类中。
答案 5 :(得分:0)
正如您在此代码中看到的那样
class Node {
//
void appendToTail( int d ) {
Node *end = new Node( d );
Node n = this;
// ...
}
}
您的班级Node
在其定义中引用了Node
。
行:Node *end = new Node( d );
表示Node
内部有另一个节点的引用。
行Node n = this;
表示在Node
内对该节点本身的引用,由this
表示。因此,n
也是对节点本身的引用。