我一直认为链接列表的好处是你可以添加或删除项目(尤其不是从最后开始),而不必复制大量的元素,这要归功于指针之美。
但是,Scala的List
是不可变的(至少在默认情况下是这样)。拥有不可变链表是有什么好处的(因为有明确的缺点,例如不是O(1)元素访问。)
谢谢!
答案 0 :(得分:15)
我认为主要原因是链接列表最强大的用途之一是头/尾分裂。有很多递归算法看起来像这样:
def listlen[A](xs: List[A], already: Int = 0): Int = xs match {
case Nil => already
case x :: rest => listlen(rest, already+1)
}
当然,名单已经知道如何获得他们的长度;这只是一个例子。重点是你拉下头部,然后用尾巴做其他事情 - 很多有用的东西都是这样的。
由于列表是 immutable ,我们可以做其他事情 - 我们可以花费尽可能多的时间来评估列表的其余部分!我们不必一气呵成;我们相信它永远不会改变。如果列表是可变的,则不会出现这种情况 - 我们需要锁定列表,阻止其他人看到它,或者我们需要制作整个事件的防御性副本,以防万一有人可能交换它。
现在,如果你真的想要一个可变列表,那么mutable.LinkedList
具有你正在谈论的好的插入属性。但是,这并不能让你在不可变的列表给你带来安心的优雅递归。
(请注意,您可以使用不可变的数组支持结构执行此操作,但是包含每个元素的集合的可能好处是您不需要保存或复制整个数组,因为您需要最后几个元素;如果列表中的早期元素不再被指向,它们可以被垃圾收集。)
答案 1 :(得分:11)
结构共享。如果在列表上执行高阶函数(map,fold等),则返回一个新的列表实例,该列表共享上一个列表的指针。
Daniel Spiewak上周在NE Scala做了关于功能数据结构的精彩演讲。见这里:http://www.nescala.org/2011/
答案 2 :(得分:6)
但是,Scala的列表是不可变的(至少在默认情况下是这样)。拥有不可变链表的好处是什么
我在这里参加派对有点晚了,但我觉得有一个重要的事情没有人做过:
除了Rex Kerr所说的,值得指出的是,通过在不可变的单链表上预先建立一个新列表是一个恒定的时间操作。您只需创建一个指向现有列表的新节点。由于列表是不可变的,因此您知道新的尾部不会发生变化,您也不需要复制任何数据。
我怀疑,你可以构建具有恒定时间操作的新的,更大但仍然是不可变的列表,并且内存占用量很小(只需要一个节点的成本)这一事实很大一部分原因是数据选择了结构。
答案 3 :(得分:5)
scala.List
是scala.collection.immutable.List
的别名。它只是众多具体集合实现中的一种。
如果您来自Java背景,请将java.util.List
与scala.collection.mutable.Buffer
等同,而不是scala.List
。
您可以在Scala 2.8 Collections Overview.中概述集合库的结构。在这里,您将找到许多其他具体实现(可变和不可变)。
答案 4 :(得分:-3)
虽然我几乎不知道scala是如何实现的。但是应该避免使用LinkedLists。
它们在当前硬件上效率低,因为遍历它们每个节点实际上导致高速缓存未命中。 缓存未命中是当今表现的主要原因。