Python笔记 - ④ 函数、递归与汉诺塔问题

Python笔记 - ④ 函数、递归与汉诺塔问题

张板书的Python的学习笔记,包括笔记与DeBug的经历。
笔记④
Python中的函数与函数递归,以及使用递归来解决汉诺塔问题


一、函数

函数是一种仅在调用时运行的代码块,可以将数据(称为参数)传递到函数中,而函数可以把数据作为结果返回。
Python中的函数定义起来比较方便,输入、输出的数据类型不需要定义,支持直接输入输出各种数据格式。

参考网站

https://www.w3school.com.cn/python/python_functions.asp

创建函数
  • 使用def来进行函数的定义,def后跟函数名;
  • 函数名后需要带括号,括号内为函数的输入,或者说是函数的因数;
  • 函数可以有输入,也可以没有,输出同样;
  • 函数输出用return;

def test_function():	# 定义函数
  print("function done")

test_function() 	#运行函数

>>>function done

def test_function2(element):	# 定义有输入的函数
  print("你的输入是" + element)

test_function2("测试输入")
>>>你的输入是测试输入

默认参数值函数

创建函数时如果只定义了需要的参数,则在调用函数时必须要在函数后的括号中定义参数,否则就会报错。
如果在定义函数时就直接定义默认参数值,就可以在后面调用函数的时候省下一些参数。


def comefrom(country = "China"):
  print("I am from " + country)

comefrom()
>>>I am from China

comefrom('USA')
>>>I am from USA

同时可以使用 key = value 语法发送参数。


import random

def test_function(who,where,do):
  print(who + "在" + where + do)

who = ["张三","李四","王二麻子"]
where = ["厨房","教室","咖啡馆"]
do = ["洗澡","打牌","上厕所"]
i,m,p = random.randint(0,2),random.randint(0,2),random.randint(0,2)

test_function(who[i],where[m],do[p])	# 参数需要按照定义函数时的顺序进行定义
>>>张三在厨房洗澡
>>>王二麻子在教室上厕所

test_function(who = "板书",do = "码代码",where = "电脑前")	# 此时的参数顺序没关系
>>>板书在电脑前码代码

有返回值的函数

使用return来在函数的最后来返回值


def test_function(who,where,do):
  return who + "在" + where + do

sentence = test_function(who = "板书",do = "码代码",where = "电脑前")

print(sentence)
>>>板书在电脑前码代码

任意参数函数

如果您不知道将传递给您的函数多少个参数,可在函数定义的参数名称前添加 *。
这样,函数将接收一个参数元组,并可以相应地访问各项:


def my_function(*kids):
  print("The youngest child is " + kids[2])

my_function("Phoebe", "Jennifer", "Rory")
>>>The youngest child is Rory

空函数

函数定义不能为空,但是如果出于某种原因写了无内容的函数定义,则使用 pass 语句来避免错误。


def myfunction:
  pass
  

二、递归

Python 也接受函数递归,这意味着定义的函数能够调用自身。

递归是一种常见的数学和编程概念。它意味着函数调用自身。这样做的好处是可以循环访问数据以达成结果。

开发人员应该非常小心递归,因为它可以很容易地编写一个永不终止的,或者使用过量内存或处理器能力的函数。但是,在被正确编写后,递归可能是一种非常有效且数学上优雅的编程方法。

例:实现一个函数recsum(N),它递归地计算从1到所有数字的和。


def recsum(N):
  if N == 1:	#	递归函数最重要的一点即设置终止条件
    return 1
  else:
    return N+recsum(N-1)

print(recsum(5))
>>>15 # 1 + 2 + 3 + 4 + 5 = 15
>

一个经典的递归函数:汉诺塔问题

问题是印度古老的传说。 世界的创立者梵天在一座神殿里留下了三根钻石棒,在最初的一根上盖上了64枚圆型金片,最大的在底部,向上依次减小。
要求在搬动金片时小的金片不能放在大的下面。
现在要将这样一组金片从第一根柱子上完全搬到另一根上,请你说出搬动的具体方案.
汉诺塔问题

分析问题,64个金片太过复杂,可以先简化问题,以三个为例进行简化推演
在这里插入图片描述
同时我们要意识到,本质问题是按照规则将所有的金片从A柱移动到空的柱子上,所以B、C两个柱子其实是等价的;

分析可以看到,如果是4个金片,可以看出相当于是在3个金片完成换柱子的基础上,在A处还有一个最大的金片;
之后将A柱上最大的金片移动到B柱子上之后,4个金片的问题就变成了将C柱上的3个金片移动到B柱上的次级汉诺塔问题(因为现在B柱上是最大的金片,其性质与地面一致)

所以,高级的汉诺塔问题可以通过一定的规律转化成次级汉诺塔问题,故我们可以利用函数的递归来解决汉诺塔问题。


def Hanoi(n,F,M,L):	# 汉诺塔问题:将n个金碟从F柱移动到L柱
    if n==1:		# 递归的终止条件:一级汉诺塔
        move(F,L)
    else:			# 非一级汉诺塔,将A柱上还剩的那一个放到B柱上,
    				#	之后转化问题未从C柱到B柱的次级汉诺塔
        Hanoi(n-1,F,L,M)	#	(非一级汉诺塔)将F塔上n-1个碟按照汉诺塔规则移动到M柱
        move(F,L)			#	将F塔上剩下的最小的金碟移动到L柱
        Hanoi(n-1,M,F,L)	#	将之前移动到M柱上的一堆从小到大的碟按照汉诺塔规则移动到L柱

def move(F,L):		#	打印出移动方式:从第一位参数(F)移动到第二位参数(L)
					#	每一次调用 move 函数就是移动了一次
					#	故数一数调用move函数的次数即汉诺塔需要移动多少次的问题
    print('把金碟从 %s 移动到 %s.'%(F,L))
        

F='A塔'
L='B塔'
M='C塔'
n=int(input('汉诺塔中有多少个金碟?'))		#	输入汉诺塔级数
Hanoi(n,F,M,L)

>>>汉诺塔中有多少个金碟?3
>>>把金碟从 A塔 移动到 B塔.
>>>把金碟从 A塔 移动到 C塔.
>>>把金碟从 B塔 移动到 C塔.
>>>把金碟从 A塔 移动到 B塔.
>>>把金碟从 C塔 移动到 A塔.
>>>把金碟从 C塔 移动到 B塔.
>>>把金碟从 A塔 移动到 B塔.

至于计数移动次数的问题,则需要使用class,给move函数添加一个不会随着函数调用刷新的计数变量,或许可以使用其他方法,在这里只写出使用class的来:


def Hanoi(n,F,M,L,mymotion):
    if n==1:
        # print('把金碟从 %s 移动到 %s.'%(F,L))
        mymotion.move(F,L)
    else:
        Hanoi(n-1,F,L,M,mymotion)
        mymotion.move(F,L)
        Hanoi(n-1,M,F,L,mymotion)

class motion():
    def __init__(self):
        self.count = 0
    def move(self,F,L):
        self.count += 1
        # print('把金碟从 %s 移动到 %s.'%(F,L))

F='A塔'
L='B塔'
M='C塔'
n=int(input('汉诺塔中有多少个金碟?'))
mymotion = motion()
Hanoi(n,F,M,L,mymotion)
print(mymotion.count)

>>>汉诺塔中有多少个金碟?3
>>>7
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值