[英]What is the time complexity of Pattern matching in scala?
时间复杂度是否取决于要匹配的内容,还是将其编译成某种形式的可以进行O(1)查找的查找表?
某些Scala的 match
语句可以编译为与Java的 switch
语句相同的字节码。 有一个注释可以确保这一点。
但是,在大多数情况下,尤其是诸如解构之类的复杂情况,它将被编译为与一系列if / else
语句相同的字节码。
通常,我不希望它们是“恒定”操作,而是“线性”操作。 无论如何,由于输入的最大检查数不会改变,通常不会超过十个。 正式地说,它具有O(1)复杂度。
有关此问题的更详细说明,请参见yǝslA的回答。
如果您担心,可以先提出最常见的案例,然后再提出其他案例。 但是,我不太在意它的性能,您的应用程序不会真正注意到它。 我更喜欢代码的可读性和正确性。
在大多数情况下,模式匹配将为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
}
在大多数情况下,我们会使用模式匹配列表(例如list)以使用::
- O(1)
进行头部和尾部拆分,因为unapply
只是在存在head
情况下简单地返回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
。 用big-O表示: T(n) = O(n)
。 因此,我们建立了O(n)
理论界限,适用于需要检查对象的所有n
属性的情况。 正如我在上面指出的那样,在大多数情况下,我们不需要检查所有属性/元素,例如当我们使用head :: tail
,其中n
被常量替换为O(1)
。 只有当我们总是做诸如head :+ tail
我们才会得到O(n)
。 对于您程序中的所有情况,我认为摊销成本仍为O(1)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.