让我们说多项式可以看作是从指数到系数的映射。例如,x ^ 3 - 2x + 5可以用地图Map(0 -> 5, 1 -> -2, 3 -> 1)
表示。我在Scala中有一个类Poly
,它将多项式表示为映射。到现在为止还挺好。现在假设我在多项式上有两个+
运算的实现。我想确定每种情况下+
操作的时间复杂度,并找出两种实现中哪一种更有效。实现如下:
根据+
Poly
上实施foldLeft
操作
class Poly(terms0: Map[Int, Double]) {
def this(bindings: (Int, Double)*) = this(bindings.toMap)
val terms = terms0 withDefaultValue 0.0
def + (other: Poly) = new Poly((other.terms foldLeft terms)(addTerm))
def addTerm(terms: Map[Int, Double], term: (Int, Double)) = {
val (exp, coeff) = term
terms + (exp -> (coeff + terms(exp)))
}
override def toString = (for ((exp, coeff) <- terms.toList.sorted.reverse)
yield coeff + "x^" + exp) mkString " + "
}
根据+
和Poly
++
上实施map
操作
class Poly(terms0: Map[Int, Double]) {
def this(bindings: (Int, Double)*) = this(bindings.toMap)
val terms = terms0 withDefaultValue 0.0
def + (other: Poly) = new Poly(terms ++ (other.terms map adjust))
def adjust(term: (Int, Double)): (Int, Double) = {
val (exp, coeff) = term
exp -> (coeff + terms(exp))
}
override def toString = (for ((exp, coeff) <- terms.toList.sorted.reverse)
yield coeff + "x^" + exp) mkString " + "
}
到目前为止我做了什么
对于第一个版本,由于HashMap上的+
操作需要有效的常量(eC)时间(根据这些performance characteristics),terms + (exp -> (coeff + terms(exp)))
需要eC时间,因此{{1需要eC时间。因此,我们可以得出结论addTerm
上的+
操作需要(几乎?)线性时间,对吗?
对于第二个版本,假设Poly
和terms
分别由n和m个元素组成。 other.terms
需要eC时间,因此adjust
需要(几乎?)O(m)时间。因此,other.terms map adjust
需要O(n)+ O(m)时间,对吗?
那么哪种实施更有效?更正/建议吗?
答案 0 :(得分:0)
他们应该在所添加的元素数量中有效地采用线性时间。您对第一个版本的分析是正确的,第二个版本中唯一的错误是++
不是O(n)+ O(m),而是O(m)中的有效线性。 ++
是反复执行+
的简写,因此两个版本差异不大。
但是,merged
中定义的HashMap
方法可以为您完成所有这些:
def + (other: Poly) = new Poly(terms.merged(other.terms) { (x, y) =>
(x._1, x._2 + y._2)
})
但是要求terms
的类型为HashMap
,这会使withDefaultValue
无法使用,因为它不会返回HashMap
。