为什么 LinkedList 不暴露它的节点 class?

Why does LinkedList not expose its Node class?

如果我从头开始开发链表,我可以在我的业务实体中存储一个指向 Node 对象的指针 class 并实现常量 O(1) removeinsertAfter 操作。在 java 标准库实现中,它们的复杂度为 O(n),在处理大型数据集时可能会有很大差异。

他们为什么不直接制作节点 class public 并在其中封装一些细节仍然使 class 本身(可能通过接口)可访问?这将使 LinkedList 更加灵活。

我们在 Apache Commons 或 Guava 中有类似 FlexibleLinkedList 的东西吗?

ListIterator

Why don't they just made the Node class public and encapsulated some details inside it still making the class itself (via interface maybe) accessable?

没有必要。

Why don't they just made the Node class public and encapsulated some details inside it still making the class itself (via interface maybe) accessable? It would make LinkedList more flexible.

已经存在。

如果您想享受基于节点的操作的好处,例如:

  • 根据当前节点给我下一个项目
  • 删除我已有的节点,而不定位它
  • 在我已有的节点后插入一些东西

你只需要使用 ListIterator 作为 list.listIterator() 编辑的 return。此方法由所有 List 提供。

这个class封装了迭代中知道当前节点的逻辑,并提供了直接使用Node的高效操作方法,例如:

  • add - 该元素紧接在将由 next()
  • 编辑的元素之前插入
  • set - 用指定的元素
  • 替换 next()previous() 编辑的最后一个元素 return
  • remove - 从列表中删除由 next()previous()
  • return 编辑的最后一个元素

同时提供方法来控制 next()previous() 的迭代。


例子

例如,您可以每隔一个元素更改一次:

LinkedList<Integer> values = new LinkedList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

int i = 0;
ListIterator<Integer> iter = values.listIterator();
while (iter.hasNext()) {
    iter.next();

    if (i % 2 == 0) {
        iter.set(100);
    }

    i++;
}

导致

[100, 2, 100, 4, 100, 6, 100, 8, 100, 10]

并且此代码在O(n)中运行,它不需要每次都重新定位节点。与

的坏等价物相比
for (int i = 0; i < list.size(); i++) {
    if (i % 2 == 0) {
        list.set(i, 100);
    }
}

由于您所述的原因,它在 O(n^2) 中运行。


隐藏的好处Node

总的来说,封装和隐藏你的私人内部运作要好得多。用户不应该关心 LinkedList 如何在幕后完成工作。

此外,如果它会暴露 Node,用户可以偷偷地编辑它们,整个列表就会变得疯狂。

例如用户可以然后

Node a = list.getNodeAtIndex(3);   
Node b = a.next;
Node c = b.next;

// Remove b
a.next = c;
c.previous = a;

不调整列表的size。所以 list.size() 现在会 return 一个错误的数字,可能会导致迭代期间崩溃。

或者你也可以引入一个危险的循环:

a.next = b;
b.next = a;

或者忘记设置 previous,导致向后迭代时 不同的列表

a.next = c;
c.previous = b;

ListIterator 确保不会发生这样的事情,同时提供相同的功能。因此,它没有将节点直接暴露给用户,而是仅以其完全控制的方法的形式暴露所需的功能。