在scala中以恒定时间连接列表?

时间:2011-06-11 12:59:17

标签: list scala data-structures concatenation

在Scala中,是否有内置函数或外部库用于在常量时间内连接两个列表(或数组,向量或列表缓冲区等)?这样的操作可能会破坏/改变两个原始列表。据我所知,我看到的用于连接列表的所有函数都以线性时间运行。

非常感谢。

4 个答案:

答案 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.DoubleLinkedListjava.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)
  }
}