Scala头/尾提取器的时间和空间复杂度是多少?

时间:2015-07-08 21:04:29

标签: scala tail-recursion tail extractor unapply

这个时间和空间的复杂性是什么:

def isPalindrome[A](x: Seq[A]): Boolean = x match {
  case h +: middle :+ t => h == t && isPalindrome(middle)
  case _ => true
}

是否取决于Seq的实施?由于IndexedSeq O(1)应该O(n)尾{vs LinearSeq O(n)由于递归调用堆栈,空间复杂度是import scala.annotation.tailrec @tailrec def isPalindrome[A](x: Seq[A]): Boolean = x match { case h +: middle :+ t => h == t && isPalindrome(middle) case _ => true } 还是Scala会自动进行尾调用优化?

{{1}}

1 个答案:

答案 0 :(得分:1)

  

是否依赖于Seq的实施?因为对于LinearSeqs,IndexedSeq应该有O(1)尾对比O(n)

我通常会假设,但提取器实际上是O(n)。任何Seq的提取器都是scala.collection.:+,其中列表的O(n)为最后一个,O(n)为最后一个。这两个代码如下:

  def init: Repr = {
    if (isEmpty) throw new UnsupportedOperationException("empty.init")
    var lst = head
    var follow = false
    val b = newBuilder
    b.sizeHint(this, -1)
    for (x <- this) { // O(n)
      if (follow) b += lst
      else follow = true
      lst = x
    }
    b.result
  }

  def last: A = {
    var lst = head
    for (x <- this) // O(n)
      lst = x
    lst
  }
  

由于递归调用堆栈,空间复杂度是否为O(n),或者Scala是否自动进行尾调用优化?

我看到代码确实有这个优化。这是有道理的,因为t && isPalindrome(middle)允许Scala关闭当前调用堆栈,将t传递给下一个堆栈&&,因此它可以进行尾递归优化。

恒定时间匹配

使用Vector我们可以实现O(1)时间:

object ends {
  def unapply[T](t: Vector[T]): Option[(T, Vector[T], T)] =
    if (t.length < 2) None
    else Some((t.head, t.drop(1).dropRight(1), t.last))
}

def isPalindrome[A](x: Vector[A]): Boolean = x match {
  case ends(i, middle, l) => i == l && isPalindrome(middle)
  case _ => true
}