演示递归的规范函数是factorial()函数。我自己尝试了一个简单的实现,并提出了这个:
factorial <- function(x){
if(x==1)
return( 1)
else
return(x*factorial(x-1))
}
根据我对该主题的调查,似乎存在一些关于使用递归或简单迭代是否更好的争论。我想看看R如何实现它并在gregmisc包中找到了factorial()函数。我以为我会找到类似于我的实现或者经常迭代的东西。我发现了这个:
> factorial
function (x)
gamma(x + 1)
<environment: namespace:base>
所以关于R是否更喜欢递归或迭代的问题的答案是“既不”。至少在这个实现中。 R中是否有充分理由避免使用递归函数?
更新
gregmisc版本:
>ptm <- proc.time()
> factorial(144)
[1] 5.550294e+249
> proc.time() - ptm
user system elapsed
0.001 0.000 0.001
我的版本:
> factorial(144)
[1] 5.550294e+249
> proc.time() - ptm
user system elapsed
0.002 0.001 0.006
答案 0 :(得分:12)
对于整数阶乘的计算,递归实现更慢且更复杂。不变的是,迭代在生产代码中使用。
您引用的factorial
函数位于基础包中。它以实际值而不是整数运行,因此实现。其文件说明:
阶乘(x)(x!表示非负数 整数x)定义为gamma(x + 1)
一个更有趣的例子是实现Fibonnaci系列的代码,当使用朴素递归实现时非常浪费。通过memoization可以使递归方法变得高效,但如果性能受到威胁,那么简单的迭代总是首选。
另一种以递归方式自然表达的常见算法是Quicksort。这可以像所有算法一样在没有递归的情况下实现,但这样做非常复杂。使用非递归Quicksort没什么好处,因此使用朴素递归实现很常见。
递归是一个很好的实现选择:
答案 1 :(得分:9)
我认为在R中表达数学计算的最自然的方式是通过数学/统计表示法。语言的全部意义在于以自然的方式表达统计计算变得容易。
您自己使用factorial
实现的gamma
示例非常适合此视图。我不知道gamma
是如何实现的,但我们不需要知道为了使用R.作为用户,最重要的是通常得到正确的答案。如果代码被证明非常慢,那就是优化时。第一个开始的地方将是数学和算法的选择,而不是实现细节。
阶乘函数和斐波纳契数也都很快增长。这意味着每个算术运算(加法,乘法等)将开始花费很长时间,而递归不会变得更加昂贵或者至少不会那么快。再次,数学考虑因素胜过实施细节。
我的建议是:
答案 2 :(得分:1)
答案是肯定的.R中使用了递归函数。虽然R的大部分本身是用R编写的,但是一些高度优化的例程是C或FORTRAN的包装器。此外,R-BASE的大部分都是原始的。基本上,除非有人真正浏览二进制文件,否则最不可能看到最常使用递归的快速例程。
递归函数的一个很好的例子可能是所有函数中最常用的函数:
> c
function (..., recursive = FALSE) .Primitive("c")
> set.seed(1)
> x <- list('a'=list(1:2, list(rnorm(10)), 'b'=rnorm(3)))
> c(x)
$a
$a[[1]]
[1] 1 2
$a[[2]]
$a[[2]][[1]]
[1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291 0.7383247
[9] 0.5757814 -0.3053884
$a$b
[1] 1.5117812 0.3898432 -0.6212406
> c(x, recursive=TRUE)
a1 a2 a3 a4 a5 a6 a7 a8
1.0000000 2.0000000 -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684
a9 a10 a11 a12 a.b1 a.b2 a.b3
0.4874291 0.7383247 0.5757814 -0.3053884 1.5117812 0.3898432 -0.6212406
>