所有函数都可以被其他函数调用,当然也可以被自己调用,这种调用方式叫做递归。递归是简化代码的一种有效手段,也是体现代码美感的重要方式。
一般的书籍或教程讲到递归的时候都会以阶乘距离,这种案例只涉及到调用自己一次,所以较为简单,也比较容易理解。但是在实际使用中,我们会遇到在一个函数里,存在两个调用自身的函数,这个分析起来就比较困难,我们必须要理解“栈”的概念,才能顺利理解调用过程。
下面利用tutle绘图库来介绍双递归函数(即在一个函数里存在两个调用本函数的函数)的执行过程,同时介绍print()函数在此类函数调试中的积极作用。
题目: 理解如下代码的运行机理: 图中标注1为第一个调用自身的函数,标注2为第二个调用自身的函数。代码中加入了很多print()语句,用来根据输出判断程序的执行过程。这段代码的执行结果为:
主函数中调用语句为:
draw(bob,100,2)从控制台输出结果我们可以看到,程序首先以 n=2 进入,再进入调用自身的函数1,再重新进入本函数,控制台输出“1 beginning”,当再次从语句1进入本函数时,出发 if 语句条件,直接跳到语句1后面开始继续执行。 (注意,此时并不会跳出整个函数结束)此时 n=1 ,所以进入语句2执行后立刻return到后面语句,执行后退语句。这时语句1当时执行过程中进栈的 n = 2 需要出栈,从语句1后面开始继续执行。执行到语句2时,再次重新进入本函数,此时 n=1 ,进入语句1再次被return到语句1后面。再次进入语句2同样被return到语句2后面。然后执行后退语句,此时 n=1 。此时语句2执行过程中进栈的 n=2 需要出栈,从语句2后面开始执行,即后退语句。 这就是整个程序执行的过程。 从以上例子可以看出,在程序执行过程中,print()语句可以帮助我们更好的了解程序的执行过程。
代码附上:
import turtle def fd(t, length): t.fd(length) def lt(t, angle): t.lt(angle) def bk(t, length): t.bk(length) def rt(t, angle): t.rt(angle) def draw(t, length, n): if n == 0: return print("%d beginning" %n) # execute from beginning or not angle = 50 fd(t, length*n) lt(t, angle) print(n) # watch the number of n draw(t, length, n-1) print("first_draw") # first recurtion function print(n) # watch the number of n rt(t, 2*angle) draw(t, length, n-1) print("second_draw") # second recursion function lt(t, angle) bk(t, length*n) print("bk and %d" %n) # watch bk and the number of n def main(): bob = turtle.Turtle() bob.pensize(4) bob.speed(1) draw(bob, 100, 2) main()