为什么Scala集合中没有不可变的双链表?

时间:2011-11-07 20:43:05

标签: scala collections linked-list immutability

查看this问题,提问者对List中某个元素的第一个和最后一个实例感兴趣,似乎更有效的解决方案是使用DoubleLinkedList可以从列表末尾向后搜索。但是,集合API中只有一个实现,它是可变的。

为什么没有不可变版本?

5 个答案:

答案 0 :(得分:14)

因为每次要进行更改时都必须复制整个列表。使用普通链接列表,您至少可以在列表前添加,而无需复制所有内容。如果您确实希望在每次更改时复制所有内容,则不需要链接列表。你可以使用不可变数组。

答案 1 :(得分:9)

这种结构存在许多障碍,但其中一个非常紧迫:双重链表不能持久。

这背后的逻辑非常简单:从列表中的任何节点,您都可以到达任何其他节点。因此,如果我将一个元素X添加到此列表DL,并尝试使用DL的一部分,我将面临这样的矛盾:从指向X的节点可以到达部分(DL)中的每个元素,但是,双链表的属性,即从部分(DL)的任何元素我可以到达指向X的节点。由于部分(DL)应该是不可变的并且是DL的一部分,并且因为DL不包括节点指向到X,那就是不可能。

非持久性不可变数据结构可能有一些用途,但它们通常对大多数操作都不好,因为每当生成衍生产品时都需要重新创建它们。

现在,创建相互引用严格对象的细微问题,但这是可以克服的。可以使用by-name参数和lazy vals,或者可以像Scala的List一样:实际创建一个可变集合,然后在不可变状态下“冻结”它(参见ListBuffer和它的toList方法)。

答案 2 :(得分:5)

因为在逻辑上不可能创建具有严格不变性的相互(循环)参照数据结构。

由于简单的存在顺序优先级,您无法创建两个相互指向的节点,因为创建另一个节点时,至少有一个节点不存在。

有可能通过涉及懒惰的技巧(通过变异实现)来获得这种循环,但真正的问题就变成了为什么你会首先想要这个东西?

答案 3 :(得分:4)

正如其他人所指出的那样,双链表没有持久的实现。您将需要某种树来接近您想要的特征。

特别是,您可能需要查看 finger trees ,它提供对前后的O(1)访问,向前和后的摊销O(1)插入,和O(log n)插入其他地方。 (这与大多数其他常用树木形成鲜明对比,这些树木在任何地方都有O(log n)访问和插入。)

另见:

答案 4 :(得分:3)

作为@KimStebel答案的补充,我想补充一点:
如果您正在搜索适合于提出问题的问题的数据结构,那么您可以Extreme Cleverness: Functional Data Structures in Scala查看@DanielSpiewak