【问题标题】:Why does LinkedList not expose its Node class?为什么 LinkedList 不公开它的 Node 类?
【发布时间】:2021-05-07 20:28:35
【问题描述】:

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

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

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

【问题讨论】:

    标签: java data-structures encapsulation doubly-linked-list


    【解决方案1】:

    ListIterator

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

    没有必要。

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

    已经存在了。

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

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

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

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

    • 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, 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() 现在会返回错误的数字,可能会导致迭代期间崩溃。

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-28
      • 2011-01-04
      • 2019-08-02
      • 2020-05-09
      • 2014-11-06
      • 1970-01-01
      • 2018-12-23
      • 2019-05-07
      相关资源
      最近更新 更多