在链表示例中,“this”是指什么?

4

我正在浏览《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


1
这不是C++。可能是Java? - Barry
2
提示:你会如何称呼 appendToTail - Happy Green Kid Naps
这绝对是Java。 - JNYRanger
@Barry 我也在想那个,问了一个朋友,他说看起来像C++。不过还是谢谢你澄清了! - secondubly
1
可能是这个程序中的"this"是什么意思?的重复问题。 - Dan
显示剩余7条评论
6个回答

3
this指的是类的一个特定实例。由于对象是构造出来的,因此可以有多个类的实例,但使用this关键字可以让您获取对自身的引用,表示对调用方法的对象特定实例的引用。
链接列表是一组节点,这些节点彼此连接。当调用appendToTail()时,节点将查看链接到自己的所有Node对象并跟随链。要获取对本身的引用以便跟随其自己的链,使用this关键字。
您还问为什么在此情况下不使用null来初始化n。这会导致NullPointerException在循环约束中首次调用n.next时发生,因此使用自己的引用作为迭代链接列表的起点。
这(双关语打算)可能是一个令人困惑的话题,但让我们使用您提供的示例。
Node n = this;
while(n.next != null) {
    n = n.next;
}

假设我们的链表当前链接了4个对象,为了简单起见,正在调用appendToTail()方法的Node对象是列表的头部。以下是上面片段中每个循环迭代所持有的Node n的引用值。
  1. 我们正在指向自己 - this
  2. 指向链表中的第二个项目。 - this.next
  3. 指向下一个项目 - this.next.next
  4. 指向列表中的最后一个项目 - this.next.next.next
循环结束,因此当前n = this.next.next.next的引用。然后,我们将n的下一个值(其中n当前指向链的末尾)设置为我们在方法开头创建的新对象,使其成为列表的新末尾。(n.next = end现在等同于this.next.next.next.next = end)。
半不必要的编辑:这是使用Java解释的。看起来在我写这个答案之后,有人添加了C++标记。

2

这是Java。

"this" 指的是调用发生的特定类的实例。在这种情况下,"this" 是指你正在处理的特定类 Node。而变量 "end" 则创建了一个 新的 和独立的 Node 类的版本,该版本使用传递的 int "d" 构建。


你的第二句话有点误导性:this并不是指类本身,否则它就是一个静态方法。相反,它指的是调用该方法的特定类实例。我不是要显得卖弄学问,但这是一个容易混淆的话题,所以只是想确保它清晰明了。 - JNYRanger
好的,说得对。后面的句子解释清楚了,但我已经编辑了您的建议。谢谢。 - ballBreaker

0

由于这是一个链表,所有节点都连接在一起,并且您有一个起始节点(根节点)。因此,在使用它时,它看起来像这样:

Node root = new Node(6); //need an instance first
root.appendToTail(5);
root.appendToTail(3);
//6->5->3

由于这些节点是连接的,我需要一个起始节点,并且需要检查它是否有下一个节点,当有下一个节点时,我需要深入搜索。当一个节点没有下一个节点时,它就是当前的最后一个节点,可以将我的新节点添加到其中。因此,在Java中,它指的是类的当前实例。在我的例子中,是root节点(因为我调用了root.appendToTail)。因此,该方法将从root节点(值为6)开始搜索下一个没有下一个节点的节点(值为3),并将其附加在那里。如果我可以获取一个子引用,并调用child3.appendToTail,则该方法将从child3开始搜索,而不是从根节点开始。

n设置为null并将while重写为从this.next走时,当您使用appendToTail的当前节点没有下一个节点并且会抛出NullPointerException时,就会遇到问题。


0

Node n = this; 的意思是n对象引用调用此方法的对象。因此,该方法循环到下一个对象,直到下一个对象为null,并将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


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的节点开始迭代,但此时该节点可以是任何东西,从头到尾。

顺便说一句,如果您手动实现链表,请确保实际拥有LinkedList类,该类将提供诸如addgetsizeappendToTail等方法,而不是将这些方法放入节点类中。


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 也是对该节点本身的引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接