"this" 在链表示例中指的是什么?

What does "this" refer to in Linked List example?

所以我正在浏览 破解编码面试 以复习一些面试内容,我 运行 浏览了这个链表实现,也许这是一个虽然但它完全超出了我的头脑。我理解其中的大部分内容,除了特定的一行,它让我失望。我将 post 下面的代码(供参考,这本书没有提到语言,但它似乎是 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 在那种情况下?

这是Java。

"this" 指的是正在调用的 class 的特定实例。在这种情况下,“this”是指您正在处理的特定 class Node。虽然变量“end”创建了一个 newNode class 的单独版本,它是使用传递的 int “d”。

this指的是class对象的具体实例。由于对象是构造出来的,所以 class 可以有多个实例,但是使用 this 关键字可以让您获得对其自身的引用,这意味着对对象的特定实例的引用,其方法正在被调用叫。

链表是节点的集合,这些节点很好地链接在一起。当您调用 appendToTail() 时,节点将查看链接到自身的所有 Node 对象并跟随链。为了让它获得对自身的引用以遵循自己的链,使用了 this 关键字。

你还问为什么在这种情况下不使用null来初始化n。当在循环约束中首次调用 n.next 时,这将导致 NullPointerException,因此它自己的引用用作链表迭代的起点。

这个(双关语)起初可能是一个令人困惑的话题,但让我们使用您提供的示例。

Node n = this;
while(n.next != null) {
    n = n.next;
}

假设我们的列表中当前链接了 4 个对象,为了简单起见,调用 appendToTail() 的 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++ 标签

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

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

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

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

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

任何节点实例都可以调用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 class 维护对头部的引用,所以您必须能够从任何给定节点进行迭代。这就是这里发生的事情,您从调用 appendToTail 的 Node 开始迭代,但此时该 Node 可以是任何东西,从头到尾。

作为旁注,如果您手动实现链表,请确保实际有 class 链表,它将提供 addget、[=21 等方法=], appendToTail 等等,而不是将它们放入节点 class.

如您在此代码中所见

class Node {
   //

   void appendToTail( int d ) {
       Node *end = new Node( d );
       Node n = this;
       // ...
   }
}  

您的 class Node 在其定义中引用了 Node

行:Node *end = new Node( d ); 表示在 Node 中有对 另一个 节点的引用。

Node n = this; 表示在 Node 中对该节点 本身 的引用由 this 表示。因此,n 也是对所述节点 本身的引用。