17 闭包和函数的递归调用(汉诺塔问题)

一.闭包

  • 在Python中,函数支持嵌套。
  • 如果在一个内部函数中对外部函数作用域(非全局作用域)的变量进行引用,那么内部函数称为闭包。闭包满足三个条件:
    1.存在于嵌套关系的函数中。
    2.嵌套的内部函数引用了外部函数的变量。
    3.嵌套的外部函数将内部函数名作为返回值返回。

示例:

def fun_out(n=0):
    count = [n]  # 外部函数内变量

    def fun_inner():
        count[0] += 1  # 引用外部函数的变量
        return count[0]

    return fun_inner  # 返回内部函数名称


quote = fun_out(5)
print(quote())  # 输出6

从变量的生命周期讲,在外部函数执行结束后,变量count将被销毁。而当外部函数执行完之后,才返回内部函数名称,才会执行内部函数。由于内部函数使用了count变量,所以程序应该出现运行时错误。
但是并没有发生这样的错误。因为闭包会记得外层函数的作用域,不会释放这个变量。

  • 那么闭包的作用是什么?是保存函数的状态信息,使函数的局部变量信息依然可以保存下来。就是保存局部变量不被销毁。

二.函数的递归调用

  • 函数在执行的过程中直接或间接调用自己本身,称为递归调用。

示例:求1~10的平方和。

def f(x):
    if x == 1:
        return 1
    else:
        return (f(x - 1) + x * x)


print(f(10))  # 输出385
  • 递归调用的执行过程分为递推过程和回归过程两部分。这两个过程由递归终止条件控制。

示例:汉诺塔问题。
相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

得出有这样几个限制条件:
1.大圆盘必须放在小圆盘下面。
2.在三根杆直接一次只能移动一个圆盘。
3.只能移动在最顶端的圆盘。

分析,求解过程就是:
1.有一个盘子的话,就是将盘子从A直接移动到C。
2.有两个盘子的话,将小盘子从A移动到B,大盘子从A移动到C。小盘子从B移动到C。
3.有n个盘子的话,视作将上面n-1个盘子和最下面第n个盘子的情况。将n-1个盘子从A移动到B,第n个盘子从A移动到C,n-1个盘子从B到C。问题再次转化为搬动n-1个盘子。继续上面的操作,直到变成只搬一个盘子的情况。

递归结束的时候,只移动一个盘子。

def move(source, target):
    print(source, '->', target)


def hanoi(n, source, temp, target):
    if n == 1:
        move(source, target)
    else:
        hanoi(n - 1, source, target, temp)  # 将n-1个盘子移动到中间杆
        move(source, target)  # 将最后一个盘子搬到目标杆
        hanoi(n - 1, temp, source, target)  # 将n-1个盘子搬到目标杆


n = int(input("输入盘子数:"))
print("步骤如下:")
hanoi(n, 'A', 'B', 'C')

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值