这只是我的好奇心,但更有效,递归还是循环呢?
给定两个函数(使用常见的lisp):
(defun factorial_recursion (x)
(if (> x 0)
(* x (factorial_recursion (decf x)))
1))
和
(defun factorial_loop (x)
(loop for i from 1 to x for result = 1 then
(* result i) finally
(return result)))
哪个更有效?
答案 0 :(得分:34)
我甚至不需要阅读你的代码。
循环对于阶乘更有效。当您进行递归时,您最多可以在堆栈上进行 x 函数调用。
出于性能原因,您几乎从不使用递归。您使用递归来使问题更简单。
答案 1 :(得分:11)
亩。
说真的,现在没关系。不是这个尺寸的例子。它们都具有相同的复杂性。如果您的代码不够快,这可能是您最后看到的地方之一。
现在,如果您真的想知道哪个更快,请测量它们。在SBCL上,您可以循环调用每个函数并测量时间。由于您有两个简单的函数,time
就足够了。如果您的程序更复杂,profiler会更有用。提示:如果您不需要用于测量的分析器,您可能不需要担心性能。
在我的机器上(SBCL 64位),我运行了你的功能并得到了这个:
CL-USER> (time (loop repeat 1000 do (factorial_recursion 1000)))
Evaluation took:
0.540 seconds of real time
0.536034 seconds of total run time (0.496031 user, 0.040003 system)
[ Run times consist of 0.096 seconds GC time, and 0.441 seconds non-GC time. ]
99.26% CPU
1,006,632,438 processor cycles
511,315,904 bytes consed
NIL
CL-USER> (time (loop repeat 1000 do (factorial_loop 1000)))
Evaluation took:
0.485 seconds of real time
0.488030 seconds of total run time (0.488030 user, 0.000000 system)
[ Run times consist of 0.072 seconds GC time, and 0.417 seconds non-GC time. ]
100.62% CPU
902,043,247 processor cycles
511,322,400 bytes consed
NIL
将函数放在顶部为(declaim (optimize speed))
的文件中后,递归时间降至504毫秒,循环时间降至475毫秒。
如果你真的想知道发生了什么,请在你的功能上试试dissasemble
并查看其中的内容。
同样,这对我来说似乎不是问题。就个人而言,我尝试使用Common Lisp作为脚本语言进行原型设计,然后分析和优化缓慢的部分。从500毫秒到475毫秒是没有。例如,在一些个人代码中,我通过简单地向数组添加元素类型来获得几个数量级的加速(因此在我的情况下使数组存储小64倍)。当然,理论上重用该数组(在使其变小之后)并且不会反复分配它会更快。但是简单地将:element-type bit
添加到它就足以满足我的需求 - 更多的更改需要更多时间才能获得额外的好处。也许我很草率,但“快”和“慢”对我来说并不重要。我更喜欢'足够快'和'太慢'。在大多数情况下,你的两个函数都“足够快”(或者在某些情况下两者都“太慢”),因此它们之间没有真正的区别。
答案 2 :(得分:8)
如果你能以这样的方式编写递归函数,使得递归调用完成的最后一件事(并且函数因此尾递归) 您使用的语言和编译器/解释器支持尾递归,然后递归函数可以(通常)优化为真正迭代的代码,并且与同一函数的迭代版本一样快。
但是,Sam I Am是正确的,迭代函数通常比它们的递归函数更快。如果递归函数与执行相同操作的迭代函数一样快,则必须依赖优化器。原因是函数调用 比跳转更昂贵,而且你消耗了堆栈空间,一个(非常)有限的资源。
您提供的函数不是尾递归,因为您调用factorial_recursion
然后将其乘以x
。尾递归版本的一个例子是
(defun factorial-recursion-assist (x cur)
(if (> x 1)
(factorial-recursion-assist (- x 1) (+ cur (* (- x 1) x)))
cur))
(defun factorial-recursion (x)
(factorial-recursion-assist x 1))
(print (factorial-recursion 4))
答案 3 :(得分:-1)
这是一个尾递归因子(我认为):
(defun fact (x)
(funcall (alambda (i ret)
(cond ((> i 1)
(self (1- i) (* ret i)))
(t
ret)))
x 1))