课程内容及目标:
- 讲解递归
- 展示递归这一概念是如何建立在概念归纳的基础之上的
- 运用递归引出递归算法的通用原理
- 分而治之
1.迭代和递归:
计算a*b的值,采用连加的方法:
(1)从迭代的角度来看,表面上,我们可以说这个计算过程只涉及两个变量,一个是迭代次数,设为i,它的初始值应该为b;另一个是状态变量,它计算我们已经进行了多少次运算,现在的结果又是怎样,初始值为0。
由此,状态变量有两个特点:一是如果计算停在任意一点,它们可以准确地告诉我自己的所在位置;二是它们不止可以被初始化,同时至少会有1个状态变量告诉我何时可以终止循环。
def iterMul(a, b):
result = 0
while b>0:
result += a
b -= 1
return result
(2)从递归的角度来看,b个a相加,相当于a与b-1个a连加后的结果相加,即a*(b-1)+a。当我们采用递归的思想时,我们做了两件事:首先,我们怎样才能使用已知的方法操作将问题转化成一个更简单的版本,这就是所谓的“递归步骤”;其次,我们将要反复思考如何将计算简化,直到它变得十分简单,我们可以直接解决它,这被称之为“基线条件”。对于这一问题,基线条件是a*b=a;if b=1,否则将执行递归步骤a*b=a+a*(b-1)
def recurMul(a,b):
if b==1:
return a
else:
return a + recurMul(a, b-1)
小结:
①每次对函数进行递归调用都会创建它自己的环境,创建变量的局部作用域。因此,在那个环境中,对该函数的主题进行求值需要非常清晰,明确它所使用的a和b的数值以及其他它所使用的变量。
②每一个框架中,变量的绑定都是不同的。并且它们中的每一个都有不同的框架与之对应。而且,当我们进行递归调用时,那些绑定都不会改变。当我们进行调用时,它们就已经设置好了。也就是说,当要计算b的一个新的数值,让它变成b-1,以便在框架中绑定。但进入另一个框架时,将不会改变这些绑定。
③控制流可以很自然地传递回一个更早的框架,只要函数调用返回了它的数值
2.阶乘问题:
(1)迭代:
def factl(n):
res = 1
while n>1:
res = res * n
n -= 1
return res
(2)递归:
def factR(n):
if n == 1:
return n
return n*factR(n-1)
3.求base的exp次幂:
①递归:
def recurPower(base, exp):
if exp == 0:
return 1
return base*recurPower(base, exp-1)
②递归进阶:
def recurPowerNew(base, exp):
if exp == 0:
return 1
elif exp>0 and exp%2==0:
return recurPowerNew(base*base, exp/2)
elif exp>0 and exp%2!=0:
return base*recurPowerNew(base, exp-1)
4.求最大公约数:
①采用迭代:
def gcdIter(a, b):
for i in range(min(a,b), 0, -1):
if i==1:
return 1
if a%i==0 and b%i==0:
return i
②递归:
利用结论——如果b=0,那么a就是最小公约数,否则,gcd(a,b)=gcd(b,a%b)
def gcdRecur(a,b):
if b==0:
return a
else:
return gcdRecur(b, a%b)
5.体现递归方法优势的问题——汉诺塔问题:
def printMove(fr, to):
print('move from '+str(fr)+' to '+str(to))
def Towers(n, fr, to, spare):
if n == 1:
printMove(fr, to)
else:
Towers(n-1, fr, spare, to)
Towers(1, fr, to, spare)
Towers(n-1, spare, to, fr)
6.菲波那切数列:(涉及多个基线条件)
def fib(x):
assert type(x) == int and x>=0 #assert为断言函数,声明的布尔值必须为真的判定,若为假则返回异常
if x==0 or x==1:
return 1
else:
return fib(x-1)+fib(x-2)
7.给定一个字符串,判断是否为回文结构:
回文结构:从左向右读和从右向左读一样,如'Able was I ere saw Elba'
第一步是要删除所有的空格和标点符号
第二步将所有字符改为小写
第三步解决问题:
①如果该字符串长度为0或1,那么该字符串就是回文结构
②否则,就要检查,字符串的首尾字母是否相同,然后再看剩下的首尾字母是否相同
def isPalindrome(s):
def toChars(s):
s = s.lower()
ans = ''
for c in s:
if c in 'abcdefghijklmnopqrstuvwxyz':
ans = ans + c
return ans
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0]==s[-1] and isPal(s[1:-1])
return isPal(toChars(s))