评估函数的性能

时间:2013-08-09 02:59:13

标签: scala recursion tail-recursion

" 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)?

最后,对于百万元素列表,后者函数在资源方面的表现会更好吗,因为它的尾递归?

1 个答案:

答案 0 :(得分:4)

  1. 关于

      
        

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

      

    不,它变为O(n^2)

  2. 对于足够大的O(n^2),尾递归不会保存O(n)算法与n; 100万肯定就足够了!


  3. 为什么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)
    • 的顺序