Mic*_*ael 5 xml scala time-complexity
这是一个后续行动,一个我以前的职位.
我试图理解为什么RuleTransformer的性能如此差.现在我认为它很慢,因为它的复杂性是O(2 n),其中n是输入XML树的高度.
假设我需要将所有元素的所有标签重命名为"b":
import scala.xml._, scala.xml.transform._
val rule: RewriteRule = new RewriteRule() {
override def transform(node: Node): Seq[Node] = node match {
case e: Elem => e.copy(label = "b")
case other => other
}
}
def trans(node: Node): Node = new RuleTransformer(rule).apply(node)
Run Code Online (Sandbox Code Playgroud)
让我们计算transform每个节点在输入中的访问次数<a3><a2><a1/></a2></a3>.
为了计算访问次数,我们添加一个缓冲区visited,在开始时初始化它,存储访问过的节点,最后打印它们.
import scala.collection.mutable.ListBuffer
// buffer to store visited nodes
var visited: ListBuffer[Node] = ListBuffer[Node]()
val rule: RewriteRule = new RewriteRule() {
override def transform(n: Node): Seq[Node] = {
visited append (n) // count this visit
n match {
case e: Elem => e.copy(label = "b")
case other => other
}
}
}
def trans(node: Node): Node = {
visited = ListBuffer[Node]() // init the buffer
val r = new RuleTransformer(rule).apply(node)
// print visited nodes and numbers of visits
println(visited.groupBy(identity).mapValues(_.size).toSeq.sortBy(_._2))
r
}
Run Code Online (Sandbox Code Playgroud)
现在让我们在REPL中运行它,然后看看 visited
scala> val a3 = <a3><a2><a1/></a2></a3>
a3: scala.xml.Elem = <a3><a2><a1/></a2></a3>
scala> trans(a3)
ArrayBuffer((<a3><b><b/></b></a3>,2), (<a2><b/></a2>,4), (<a1/>,8))
res1: scala.xml.Node = <b><b><b/></b></b>
Run Code Online (Sandbox Code Playgroud)
因此a1被访问了八次.
如果我们变换<a4><a3><a2><a1/></a2></a3></a4>那么a1将被访问16次,为<a5><a4><a3><a2><a1/></a2></a3></a4></a5>-32,等等.因此复杂性看起来是指数级的.
是否有意义 ?你会如何通过分析代码证明它?
这不是一个非常严格的分析,但问题似乎是BasicTransformer的变换(Seq [Node])方法[1].
子变换方法将针对更改的节点调用两次.特别是在您的示例中,由于这个原因,将调用所有节点两次.你是对的,高度为h的每个节点将被称为2 ^(h-1)次.另请注意,节点的最多一个子节点将被调用两次,因为使用了span和代码,在特定示例中,节点的所有子节点将被调用两次.
只是为了验证这是为修改后的RulesTransformer写了这些代码示例.(我也可以覆盖RulesTransformer.但无论如何)
// This is same as library RuleTransformer added with print statement
class CopiedRuleTransformer(rules: RewriteRule*) extends BasicTransformer {
override def transform(n: Node): Seq[Node] = {
println(n)
rules.foldLeft(super.transform(n)) { (res, rule) => rule transform res }
}
}
Run Code Online (Sandbox Code Playgroud)
我修改过的RuleTransformer
class MyRuleTransformer(rules: RewriteRule*) extends BasicTransformer {
override def transform(n: Node): Seq[Node] = {
println(n)
rules.foldLeft(super.transform(n)) { (res, rule) => rule transform res }
}
override def transform(ns:Seq[Node]): Seq[Node] = {
ns.flatMap(n => transform(n))
}
}
Run Code Online (Sandbox Code Playgroud)
这些代码仅用于演示目的.你可以称之为
new CopiedRuleTransformer(rule).apply(node)
Run Code Online (Sandbox Code Playgroud)
要么
new MyRuleTransformer(rule).apply(node)
Run Code Online (Sandbox Code Playgroud)