在Scala中,是否有内置函数或外部库用于在常量时间内连接两个列表(或数组,向量或列表缓冲区等)?这样的操作可能会破坏/改变两个原始列表。据我所知,我看到的用于连接列表的所有函数都以线性时间运行。
非常感谢。
答案 0 :(得分:12)
有UnrolledBuffer
concat
方法使用另一个UnrolledBuffer
并在O(1)
中返回其连接。它对参数缓冲区具有破坏性 - 在调用此方法之后,第二个缓冲区将为空。
答案 1 :(得分:2)
函数式语言中的经典(回到至少Hughes '84)方法来解决常量时间追加是通过"difference lists",其中附加到列表的编码为函数组合。
这是Haskell的草图:
newtype DList a = DL { unDL :: [a] -> [a] }
所以DList是从列表到列表的函数。一些介绍形式:
-- The empty list is the identity function
empty = DL id
-- Singletons are the compositions of the cons function
singleton = DL . (:)
-- Appending two lists is just composition
append xs ys = DL (unDL xs . unDL ys)
完整的实现是on Hackage,并且转换为Scala应该是微不足道的。
答案 2 :(得分:1)
我认为DoubleLinkedList
可以提供一个常量时间附加,因为你可以将一个列表的末尾加到另一个列表的开头,而不必遍历任何一个。
但是,scala.collections.mutable.DoubleLinkedList
或java.util.List
都没有这样做。
原因可能是a.append(b)
会修改 a 和 b ,这是出乎意料的。
答案 3 :(得分:0)
这是一个简单的不可变数据结构,支持恒定时间连接。它只是表明它是可能的,但不是为了实际使用。检索元素的items
实现的运行时间非常糟糕,可以通过使用迭代器遍历树来轻松改进。
我想知道是否有更好的数据结构?
sealed abstract class Tree[+T] {
def items: List[T]
def append[U >: T](v: U): Tree[U] = this append Leave(v)
def append[U >: T](other: Tree[U]) = Node(this, other)
}
case class Node[+T](val left: Tree[T], val right: Tree[T]) extends Tree[T] {
def items = left.items ++ right.items
}
case class Leave[+T](val value: T) extends Tree[T] {
def items = List(value)
}
case object EmptyTree extends Tree[Nothing] {
def items = Nil
}
object ConstantTimeConcatenation {
def main(args: Array[String]) {
val first = EmptyTree append 1 append 2 append 3
val second = EmptyTree append 4 append 5
val both = first append second // runs in linear time
println(both.items)
}
}