【问题标题】:Evaluating Performance of Functions评估功能的性能
【发布时间】:2013-08-09 02:59:12
【问题描述】:

“oneToEach”函数将List[Int] 的每个元素加1。第一个函数不是尾递归的,而后者是。

如果我将一百万长度的 List[Int] 传递给这两个函数,那么哪个函数的性能会更好?更好 = 更快或更少的资源使用。

// Add one to each element of a list
def oneToEach(l: List[Int]) : List[Int] =
  l match {
   case Nil => l
   case x :: xs => (x + 1) :: oneToEach(xs)
}

...

def oneToEachTR(l: List[Int]) : List[Int] =  {
  def go(l: List[Int], acc: List[Int]) : List[Int] = 
     l match {
       case Nil => acc
       case x :: xs => go(xs, acc :+ (x + 1))
     }
  go(l, List[Int]())
}

如果我理解的话,第一个函数的算法复杂度为 O(n),因为需要递归遍历列表的每个项目并加 1。

对于oneToEachTR,它使用:+ 运算符,我知道read 是O(n) 复杂度。由于对列表中的每个递归/项目使用此运算符,最坏情况的算法复杂度是否变为 O(2*n)?

最后,对于百万元素的List,后一个函数是尾递归的,在资源方面表现会更好吗?

【问题讨论】:

    标签: scala recursion tail-recursion


    【解决方案1】:
    1. 关于

      对于oneToEachTR,它使用:+ 运算符,我读过它是O(n) 复杂性。由于对列表中的每个递归/项目使用此运算符,最坏情况下的算法复杂度是否变为O(2*n)

      不,它变成O(n^2)

    2. 对于足够大的n,尾递归不会保存O(n^2) 算法与O(n);一百万当然够了!


    为什么是 O(n^2)?

    • 您有一个n 元素列表。
    • 第一次调用:+ 将遍历0 个元素(acc 最初为空)并追加1:1 个操作
    • 第二次调用将遍历 1 个元素并追加 1 个:2 次操作
    • 第三次调用.. 2 个元素 + 追加 1:3 次操作
    • ...
    • 所有“操作”的总和是1 + 2 + 3 + ... + n = n(n+1)/2 = (1/2)n^2 + n/2。这是“按照”n^2O(n^2) 的顺序。

    【讨论】:

      猜你喜欢
      • 2015-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-29
      • 2014-04-15
      • 2021-12-29
      • 2020-01-13
      相关资源
      最近更新 更多