lisp函数的空间和时间复杂性

时间:2018-01-18 09:54:10

标签: algorithm lisp time-complexity space-complexity

以下是两个lisp的功能

(defun fact (x &optional (acc 1))
  (if (zerop x) acc
      (fatt (- 1 x) (* x acc))))

(defun fatt (x)
  (if (zerop x) 1
      (* x (fatt (- x 1)))))

如何找到此功能的空间和时间复杂度?

1 个答案:

答案 0 :(得分:1)

第一个功能的(更正版本)

(defun fact (x &optional (acc 1))
  (if (zerop x) 
      acc
      (fact (- x 1) (* x acc))))

当使用(fact N)调用时,时间复杂度为O(N),因为每个递归级别的步骤相同,并且有N个递归调用。空间复杂性取决于编译器。

每个体面的LISP编译器都进行尾递归优化,因此fact的递归调用被“跳转”替换为fact函数的开头,参数被新的替换。所以你只有一组变量xacc,意思是O(1)。

当然,对于一个愚蠢的编译器,你最终会得到N个调用堆栈帧,每个帧都有自己的一组变量xacc,意思是O(N)。

第二个功能

(defun fatt (x)
  (if (zerop x) 
      1
      (* x (fatt (- x 1)))))

没有(通常 - 可能有一些非常聪明的编译器......)允许尾递归优化,因此,当使用(fatt N)调用时,最终时间和空间都是O( N)。

<强>吹毛求疵

如果使用大N值,计算将不再适合fixnum数字范围并改为使用bignums,然后违反所有递归调用执行相同步骤的假设。实际上,乘法和减法之类的执行时间随着数字的长度而增加。对于适合计算机内存的阶乘,每一步都可能是O(log(x))而不是O(1)。因此对于大数字,我们将观察到O(NlogN)而不是O(N)。