我目前正在编程类中教授递归。我注意到我的学生很难掌握递归的概念。有没有一种很好的方法可视化函数对于教学目的的作用?
作为一个例子,这里有一个用于获得第n个斐波纳契数的R函数:
fib_r <- function(n) {
if(n <= 2) return(1)
fib_r(n-1) + fib_r(n-2)
}
感谢。
答案 0 :(得分:4)
这就是我在R
中解释递归函数的方法:
首先,我同意@AEBilgrau的说法,因子是递归的一个很好的例子。 (在我的选择中比斐波纳契更好。)
然后我会快速通过理论基础,为什么可以将阶乘定义为递归函数,这很简单,如
4! = 4 * 3 * 2 * 1 = 4 * 3!
然后你可以向他们展示相应的递归R
函数
fact=function(x) if (x==0) return(1) else return(x*fact(x-1))
fact(3)
#6
但还会向他们展示以下输出
#|fact(3) called
#|fact(3) is calculated via 3*fact(2)
#|fact(2) is unknown yet. Therefore calling fact(2) now
#|Waiting for result from fact(2)
#| fact(2) called
#| fact(2) is calculated via 2*fact(1)
#| fact(1) is unknown yet. Therefore calling fact(1) now
#| Waiting for result from fact(1)
#| | fact(1) called
#| | fact(1) is calculated via 1*fact(0)
#| | fact(0) is unknown yet. Therefore calling fact(0) now
#| | Waiting for result from fact(0)
#| | | fact(0) called
#| | | fact(0)=1 per definition. Nothing to calculate.
#| | | fact(0) returning 1 to waiting fact(1)
#| | fact(1) received 1 from fact(0)
#| | fact(1) can now calculate 1*fact(0)=1*1=1
#| | fact(1) returning 1 to waiting fact(2)
#| fact(2) received 1 from fact(1)
#| fact(2) can now calculate 2*fact(1)=2*1=2
#|fact(3) received 2 from fact(2)
#|fact(3) can now calculate 3*fact(2)=3*2=6
#[1] 6
源自
#helper function for formatting
tabs=function(n) paste0("|",rep("\t",n),collapse="")
fact=function(x) {
#determine length of call stack
sfl=length(sys.frames())-1
#we need to define tmp and tmp1 here because they are used in on.exit
tmp=NULL
tmp1=NULL
#on.exit will print the returned function value when we exit the function ...
#... i.e., when one function call is removed from the stack
on.exit({
if (sfl>1) {
cat(tabs(sfl),"fact(",x,") returning ",
tmp," to waiting fact(",x+1,")\n",sep="")
}
})
cat(tabs(sfl),"fact(",x,") called\n",sep="")
if (x==0) {
cat(tabs(sfl),"fact(0)=1 per definition. Nothing to calculate.\n",sep="")
#set tmp for printing in on.exit
tmp=1
return(1)
} else {
#print some info for students
cat(tabs(sfl),"fact(",x,") is calculated via ",x,"*fact(",x-1,")\n",sep="")
cat(tabs(sfl),"fact(",x-1,
") is unknown yet. Therefore calling fact(",x-1,") now\n",sep="")
cat(tabs(sfl),"Waiting for result from fact(",x-1,")\n",sep="")
#call fact again
tmp1=fact(x-1)
#more info for students
cat(tabs(sfl),"fact(",x,") received ",tmp1," from fact(",x-1,")\n",sep="")
tmp=x*tmp1
cat(tabs(sfl),"fact(",x,") can now calculate ",
x,"*fact(",x-1,")=",x,"*",tmp1,"=",tmp,"\n",sep="")
return(tmp)
}
}
fact(3)
答案 1 :(得分:3)
这是我的例子,可能在很多教科书中使用过:
recursive_sum <- function(n){
if(n == 1) {print("Remember 1, add everything together"); return(n)}
print(paste0("Remember ", n, ", pass ", n-1, " to recursive function"))
n + recursive_sum(n-1)
}
输出:
> recursive_sum(4)
[1] "Remember 4, pass 3 to recursive function"
[1] "Remember 3, pass 2 to recursive function"
[1] "Remember 2, pass 1 to recursive function"
[1] "Remember 1, add everything together"
[1] 10
答案 2 :(得分:2)
我认为阶乘函数是递归的一个很好的例子。将其与打印输出结合起来(正如其他人建议的那样)似乎是描述正在发生的事情的好方法:
factorial <- function(n) {
cat("factorial(", n, ") was called.\n", sep = "")
if (n == 0) {
return(1)
} else {
return(n * factorial(n - 1))
}
}
factorial(4)
#factorial(4) was called.
#factorial(3) was called.
#factorial(2) was called.
#factorial(1) was called.
#factorial(0) was called.
#[1] 24
然后,您还可以实现非递归因子函数并比较计算效率。或者也许问他们上面的实现有什么问题(例如factorial(-4)
会发生什么)。
关于更合适的可视化(而不仅仅是简单的示例),有websites来说明递归树。
修改: Googling recursion也是一个有用的课程。
答案 3 :(得分:0)
在 fib_r
中打印变量 n 的值print("iteraction at: ", n)