终极奥义之——递归

递归

递归概念

直接或间接地调用自身的算法称为递归算法,用函数自身给出定义的函数称为递归函数。

  • 为了描述问题的某一状态,必须用到它的上一状态;而描述上一状态,又必须用到它的上一状态…这种用自已来定义自己的方法,称为递归定义

递归的两个要素

  • 递归边界条件。也就是所描述问题的最简单情况,它本身不再使用递归的定义。

  • 递归定义:使问题向边界条件转化的规则。递归定义必须能使问题越来越简单。
    如:f(n)由f(n-1)定义,越来越靠近f(0),也即边界条件。

例子

下面将通过几个简单的例子来简单的体会下递归

1、阶乘函数

阶乘函数可递归地定义为:
n ! = { 0 n=0, 边界条件 n ( n − 1 ) n>0, 递归方程 n!= \begin{cases} 0& \text{n=0,} & \text{边界条件}\\ n(n-1)& \text{n>0,} & \text{递归方程} \end{cases} n!={0n(n1)n=0,n>0,边界条件递归方程
边界条件与递归方程是递归函数的两个要素,递归函数只有具备了这两个要素,才能在有限次计算后得出结果。

2、斐波那切数列

无穷数列1,1,2,3,5,8,13,21,34,55,…,被称为Fibonacci数列。它可以递归地定义为
F ( n ) = { 1 n=0,1 边界条件 F ( n − 1 ) + F ( n − 2 ) n>1, 递归方程 F(n)= \begin{cases} 1& \text{n=0,1} & \text{边界条件}\\ F(n-1) + F(n-2)& \text{n>1,} & \text{递归方程} \end{cases} F(n)={1F(n1)+F(n2)n=0,1n>1,边界条件递归方程

第n个Fibonacci数可递归地计算如下:

def fibonacci(n):
    if n <= 1: return 1
    return fibonacci(n-1)+fibonacci(n-2)

上面的例子本身的递归关系太明显了,一眼就能看出来,下面来个不太容易看出来的~

3、整数划分问题

将正整数n表示成一系列正整数之和:n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1,k≥1。正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
例如:
3有3种不同的划分;
3;
2+1;
1+1+1。

4有5种不同的划分;
4;
3+1;
2+2,2+1+1;
1+1+1+1。

6有11种不同的划分:
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1。

如果设p(n)为正整数n的划分数,比较难以找到递归关系。。
因此考虑增加一个自变量:将最大加数n1不大于m的划分个数记作q(n,m)。可以建立q(n,m)的如下递归关系。

这句话又什么加数,什么划分个数比较难理解,需要慢慢体会,大体描述一下就是:
q(n,m) 中的n就是要划分的数,m就是划分的加数中最大的数,比方说上面6中间有一种划分方式:3+1+1+1,这里m就等于3.

好的,理解了新增自变量m之后开始分情况讨论边界条件及递归方程:

  1. n=1,q(1,m) 表示对1来划分,结果当然就是1了

  2. m=1,q(n,1) 表示划分的这个数只能用1来划分,那不就是1+1+…+1,当然还是一种了。

  3. n=m,q(n,n) 表示划分没有限制,这里还是要分两种情况:
    1)划分的数包含自己本身,比方说3,划分成3自己,只有一种方式
    2)不包含自己本身,也就是划分出来的数都小于自己,如3划分出来的数2及2以下都可以
    那就是1+q(n,m-1)

  4. n<m ,这时候划分出来的最大数比自己还大。。那不就是自己本身,所以也就是q(n,n)

  5. n>m,q(n,m) 最重要的一个,对n划分出来的最大数要小于m,还是上面的例子:
    1) 比方说以q(6,4),对6划分出来的数最大是4为例:也就是q(6,4),对6划分出来的数包含4本身,(9种情况)
    4+2,4+1+1;
    -----------------------------------不包含:
    3+3,3+2+1,3+1+1+1;
    2+2+2,2+2+1+1,2+1+1+1+1;
    1+1+1+1+1+1。
    下方不包含4本身的递归方程为q(n,4-1)
    所以,这个例子中q(n,m) = q(6-4, 4)+ q(6,4-1) =9
    2) 在以q(6,5),对6划分出来的数最大是5为例:q(6,5),对6划分出来的数包含5本身:
    5+1;
    --------------------------------不包含:
    4+2,4+1+1;
    3+3,3+2+1,3+1+1+1;
    2+2+2,2+2+1+1,2+1+1+1+1;
    1+1+1+1+1+1。
    同样的下方不包含5本身的递归方程为q(n,5-1)
    所以,这个例子中q(n,m) = q(6-5, 4)+ q(6,5-1) =10

    仔细体会下,递归方程可以写成q(n,m) = q(n-m, m)+ q(n,m-1)

所以根据以上分析:
q ( n , m ) = { 1 n=1,m=1 q ( n , n ) n<m, 1 + q ( n , n − 1 ) n=m, q ( n , m − 1 ) + q ( n − m , m ) n>m>1 q(n,m)= \begin{cases} 1& \text{n=1,m=1}\\ q(n,n)& \text{n<m,}\\ 1 + q(n,n-1)& \text{n=m,}\\ q(n,m-1) + q(n-m,m)& \text{n>m>1}\\ \end{cases} q(n,m)=1q(n,n)1+q(n,n1)q(n,m1)+q(nm,m)n=1,m=1n<m,n=m,n>m>1

def q(n,m):
    if n==1 or m==1: return 1
    elif n<m: return q(n,n)
    elif n==m: return 1+q(n,n-1)
    else: return q(n-m,m)+q(n,m-1)
q(6,6)
# 11

4、Hanoi塔(汉诺塔)

汉诺塔问题算是非常经典的递归例题了,可以说搞懂了这个,也就懂了大半部分的递归~

设a,b,c是3个塔座。开始时,在塔座a上有一叠共n个圆 盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,…,n,现要求将塔座a上的这一叠 圆盘移到塔座b上,并仍按同样顺序叠置。在移动圆盘 时应遵守以下移动规则:

规则1:每次只能移动1个圆盘;
规则2:任何时刻都不允许将较大的圆盘压在较小的圆盘 之上;
规则3:在满足移动规则1和2的前提下,可将圆盘移至a,b,c中任一塔座上。
在这里插入图片描述
1.首先理解题目,
输入参数: A、B、C三个塔外加加盘子个数n
输出:总移动次数,(当然移动过程也可以输出)

2.开始找规律,将问题变成数学问题
1)n=1时:只有1个盘子,A–>B ,总共1次

2)n=2时:2个盘子,总共3次

第一次 1号盘 A-->C
第二次 2号盘 A-->B
第三次 1号盘 C-->B

3)n=3时:3个盘子,总共7次

第1次  1号盘  A---->B
第2次  2号盘  A---->C
第3次  1号盘  B---->C
第4次  3号盘  A---->B
第5次  1号盘  C---->A
第6次  2号盘  C---->B
第7次  1号盘  A---->B  

在这里插入图片描述
不难发现规律,移动总次数为:2n - 1

移动规律为:

  1. 把n-1个盘子由A 移到 C
  2. 把第n个盘子由 A移到 B
  3. 把n-1个盘子由C 移到 B
cnt = 0
def move(n, x, y):
    global cnt
    cnt+=1
    print(f'第{str(cnt)}次, move{str(n)}号盘:{x}--->{y}')

def hanoi(n, A, B, C):
    if n == 1: move(1, A, B)
    else:
        hanoi(n - 1, A, C, B)  		# 将n-1个盘子由A经过B移动到C
        move(n, A, B)               # 最大盘子A移动到B
        hanoi(n - 1, C, B, A)  		# 剩下的n-1盘子,由C经过A移动到B

hanoi(3, 'A', 'B', 'C')
print(f'共计{str(cnt)}次')
"""
第1次, move1号盘:A--->B
第2次, move2号盘:A--->C
第3次, move1号盘:B--->C
第4次, move3号盘:A--->B
第5次, move1号盘:C--->A
第6次, move2号盘:C--->B
第7次, move1号盘:A--->B
共计7次
"""

小结

优点:

结构清晰,可读性强,而且容易用数学归 纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。

缺点:

递归算法的运行效率较低,无论是耗费的 计算时间还是占用的存储空间都比非递归算法要多。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值