微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 LinkedList 不公开其 Node 类?

如何解决为什么 LinkedList 不公开其 Node 类?

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

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

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

解决方法

ListIterator

为什么他们不只是将 Node 类公开并在其中封装一些细节仍然使类本身(可能通过接口)可访问?

没有必要。

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

那个已经存在了。

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

  • 根据当前节点给我下一项
  • 删除我已有的节点,不定位它
  • 在我已经拥有的节点之后插入一些内容

您只需要使用 list.listIterator() 返回的 ListIterator。此方法由所有 List 提供。

该类封装了在迭代中知道当前节点的逻辑,并提供了直接使用Node进行操作的有效方法,例如:

  • add - 元素被插入到 next()
  • 返回的元素之前
  • set - 用指定的元素替换 next()previous() 返回的最后一个元素
  • remove - 从列表中删除 next()previous()
  • 返回的最后一个元素

同时提供使用 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,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() 现在会返回错误的数字,可能会导致迭代过程中崩溃。

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

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

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

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

ListIterator 确保此类事情不会发生,同时提供相同的功能。因此,它不是直接向用户公开节点,而是仅公开所需的功能,并以完全控制的方法的形式公开。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。