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