scala 中模式匹配的时间复杂度是多少?



时间复杂度是取决于匹配的内容,还是编译成某种形式的查找表,可以执行 O(1) 查找?

一些Scalamatch语句可以编译为与Java的switch语句相同的字节码。有一个注释可以确保这一点。
但是,在大多数情况下,尤其是像解构这样的复杂情况,它将被编译为与一系列if / else语句相同的字节码。

一般来说,我不希望它们是">恒定"操作,而是"线性">操作。 无论如何,由于输入的最大检查次数不会改变,通常不会超过十个。正式地说,它有O(1)的复杂性。
有关更详细的解释,请参阅 yǝsʞǝlA 的答案。

如果您担心它,您可以将最常见的情况放在第一位,然后再放置其他情况。但是,我不会真正关心它的性能,您的应用程序不会真正注意到它。相反,我更喜欢代码的可读性和正确性。

在大多数情况下,模式匹配是O(1)的,因为您通常与少量或可能的情况进行匹配,并且每个匹配平均由几个常量时间操作组成。

由于模式匹配是通过在匹配的对象文档上调用unapply方法并选择性地比较提取的值来实现的,因此时间复杂度将取决于unapply方法的实现,并且可以具有任何复杂性。对于一般情况,无法进行编译器优化,因为某些模式匹配取决于传递给它们的数据。

比较这些方案:

List(1, 2, 3) match {
case  _ :+ last => ... // O(n) with respect to list length
case head :: tail => ... // O(1) w.r.t. list length
case _ => ... // O(1) - default case, no operation needs to be done
}

大多数时候,我们会模式匹配类似列表的东西,以::-O(1)因为unapply只是返回head如果存在的话。

我们通常不使用:+,因为它不常见且昂贵(库代码):

/** An extractor used to init/last deconstruct sequences. */
object :+ {
/** Splits a sequence into init :+ last.
* @return Some((init, last)) if sequence is non-empty. None otherwise.
*/
def unapply[T,Coll <: SeqLike[T, Coll]](
t: Coll with SeqLike[T, Coll]): Option[(Coll, T)] =
if(t.isEmpty) None
else Some(t.init -> t.last)
}

为了得到序列的最后一个元素(t.last),我们需要循环,即O(n)

因此,这实际上取决于您的模式匹配方式,但通常您模式匹配大小写类,元组,选项,集合以获取第一个元素而不是最后一个元素等。在绝大多数情况下,您将获得O(1)时间复杂性和大量的类型安全性。

此外:

在最坏的情况下,将有m模式,每个模式平均执行c操作来执行匹配(这假设unapply具有恒定的时间,但也有例外)。此外,将有一个具有n属性的对象,我们需要将其与这些模式进行匹配,这为我们提供了总共:m * c * n操作。但是,由于m非常小(模式永远不会动态增长,通常由人类编写),我们可以放心地将其称为常b,给我们:T(n) = b * c * n。在大O方面:T(n) = O(n).因此,我们建立了O(n)的理论界限,适用于我们需要检查对象的所有n属性的情况。正如我在上面指出的那样,在大多数情况下,我们不需要检查所有属性/元素,例如当我们使用head :: tail时,n被常量替换并且我们得到O(1)。只有当我们总是做这样的事情时head :+ tail我们才会得到O(n).摊销成本我相信对于您计划中的所有情况仍然O(1)

最新更新