以汉诺塔算法与阶乘函数为例子浅谈迭代算法
什么是递归与递归要点
递归:调用函数本身的函数叫做递归
要点:确定递归的结束点,更新参数
汉诺塔算法
我个人对汉诺塔的算法也还算比较深入的研究过,可以说是比较全面的理解。完全理解hannoi tower的算法对整个迭代算法的理解会到达一个很高的程度,原则上来说,所有的循环loop都可以用迭代来实现,但是有一些算法,无法确定迭代的次数,就不能用循环算法,只能用递归,而汉诺塔就是一个非常好的例子。
汉诺塔规则
汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
步骤==和把大象装冰箱里一样多
但是实现之前,我们还有两个大的步骤,第一就是理解算法
第二是代码实现。
理解算法:
A中有N个盘子,B , C柱子中没有盘子,我们要把A上的盘子放到C上面去。
判断一下,分成两种情况。第一 只有一个盘子,第二 有两个以上的盘子。这是不同两种情况,就像阶乘函数中0的阶乘等1,是与其他的情况下的结果不一致的。
只有一个盘子,那太简单了,就直接放到C上,A–>C
如果A上有两个以上的盘子,那我们分三步,第一把第一个盘子中的N-1个东西,经过N-2次迭代都放到B上,包括接下来的第二步。第二,这时候A上还剩最大的那个块,A上最大的那块放到C上,最后在把B的N-1块东西经过N-2次迭代都放到C上,就完事了。这个过程一直重复N-1次,加上第一次,一共是N次。
代码实现:
def hanoi_tower(n, a, b, c):
if n == 1:
print(a,'-->',c)
else:
hanoi_tower(n-1, a, c, b)
print(a,'-->',c)
hanoi_tower(n-1, b, a, c)
希望大家不要忘记你写这个函数的意义,这个函数的意义就是
我要把a,经过n次迭代,绕过b, 放到c上。这个函数上的表现就是hanoi_towe(n-1, a, c, b)
其实最后一次就是B上的那块放到C上面,因为这个函数最后一次迭代就是hanoi(n-1, b,a, c)
但是只有一次的话,就是会直接从A放到C。
迭代过程 :首先是到达循环终点,然后从终点一层一层向外返回值。就是从1 到N的这种递归打印函数中第二个print(a, ‘–>’, c)的那行代码,每递归一次他就会打印一次所以,总次数就是 2**(n-1)+1次。
注意我们只是打印了这种移动,这种移动其实在函数中就已经实现了,我们只是打印出来,能看见而已。
如果想知道打印了多少次,也不难。见以下代码即可。
t = 0
def hanoi_tower(n, a, b, c):
global t
if n == 1:
print(a,'-->',c)
t += 1
else:
hanoi_tower(n-1, a, c, b)
print(a,'-->',c)
t += 1
hanoi_tower(n-1, b, a, c)
hanoi_tower(2, "A",'B','C')
print('总次数为', t)
对于迭代函数实现过程,可以参考一下函数阶乘中的脚手架打印。帮助理解。
阶乘函数的递归表达
这个算法是我引用《Think Python : How to think like a Computer Scientist, Second Edition》,因为我个人也写过斐波那契的函数,但是我觉得最好理解的。个人觉得把复杂的问题简单化的算法才是一种牛X的算法。
def factorial(n):
space = ' ' * (n * 4)
print(space, 'factorial', n)
if n == 0:
print(space, 'returning 1')
return 1
else:
recurse = factorial(n-1)
result = n * recurse
# 注意,result为一个指向n*一个函数的对象,这个函数必须要有返回值
# 如果 注释掉 return,就会造成TypeError: unsupported operand type(s) for *: 'int' and 'NoneType',打印factorial不会受影响,因为这个函数是先打印,后进入递归。 报错会在return 1 之后。
# 反过来说,如果替换掉这种 result 这种指向对象,迭代是不需要有返回值的
# 跑题了,看看结果吧。
print(space, 'returning', result)
return result
factorial(4)
这段代码可以说很不错。答案为:
解释一下:其中
recurse = 1f(0) = = 11
recurse = 2f(1) == 21
recurse = 3f(2) == 32
recurse = 4f(3) == 46
recurse = n * f(n-1)
只有到达递归终点以后,才会有返回值,f()函数才能运行,所以n的变化为
4321 1234,递归是反着来的,因为这个f()还没有返回值,直到f()中有return出现。
' ', 'factorial', 4
' ', 'factorial', 3
' ', 'factorial', 2
' ', 'factorial', 1
'', 'factorial', 0
'', 'returning 1'
' ', 'returning', 1
' ', 'returning', 2
' ', 'returning', 6
' ', 'returning', 24