文科生快速入门python(十二) | 经典的函数递归案例

文科生快速入门python(十二) | 经典的函数递归案例

今天,数据猿重点整理了python的递归函数相关内容,递归函数是特殊的函数结构,在理解起来也相对较难,但是在个别问题上如果使用递归,将极大地简化代码,符合The Zen of Python的要求。

在python命令行中,输入import this ,即可打印python之禅

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

本文目录如下:

image

函数与递归的关系

  • 递归的实质:整个递归本身就是一个函数,需要函数定义描述。

  • 函数内部使用分支语句对输入参数进行判断

  • 递归函数的分支由基例和链条组成。基例是可以确定运算的分支,链条是进行递归的分支。

最基本的递归函数:计算阶乘


def fact(n):

    if n == 0:

        return 1

    else:

        return n*fact(n-1)

img

当然,阶乘最简单的方式是直接使用math库的factorial()函数


import math

math.factorial(n)

也可以使用for循环


def fact1(n):

    result = 1

    for i in range(1,n+1):

        if i == 1:

            result = 1

        else:

            result = i * result

    return result

fact1(6)

经典算法案例:汉诺塔问题

汉诺塔问题实际上是算法中的动态规划问题,也是经典算法题之一。

汉诺塔的来源

汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

抽象化后的汉诺塔问题

有三个立柱A、B、C。A柱上穿有大小不等的圆盘N个,较大的圆盘在下,较小的圆盘在上。要求把A柱上的圆盘全部移到C柱上,保持大盘在下、小盘在上的规律(可借助B柱)。每次移动只能把一个柱子最上面的圆盘移到另一个柱子的最上面。请输出移动过程。

img

汉诺塔问题的解答

这是动态规划问题中的一种,用递归来实现较为简单方便。

我们先归纳思想来思考一下,我们乍一看难想象第一步应该怎么,我们的没经过训练的大脑,很难想象应该怎么选择每一步的操作,任意选择的话,很容易出错宕机。

所以,我们换一种归纳方式,先假设除最下面的盘子之外,我们已经成功地将上面的63个盘子移到了中介柱子B柱,此时只要将最下面的盘子由开始柱子A移动到目标柱子C即可。

img

这个时候,要想完成,我们又把A当作是目标柱子,B当作开始柱子,C当作中介柱子。

所以,对于"将n个圆盘从A柱移动到C柱(借助B柱)"这个问题,我们可以通过以下三步实现:

  • 将A柱最上面的n-1个圆盘移动到B柱(借助C柱)。
  • 将A柱上剩下的那1个圆盘直接移动到C柱
  • 将B柱上的n-1个圆盘移动到C柱(借助A柱)。

汉诺塔问题的python实现

根据以上分析,我们可以得出,汉诺塔游戏的python实现代码比较简单,只需要设定好参数和基例分支、链条分支即可。

  • 参数:包括n-圆盘数量、 start、end、mid-三个柱子的名字;

  • 分支:假设开始柱子已经剩下了最底层的那个圆盘n,形成递归函数的基例,最底层以上的圆盘(n-1)已经移动到中介柱子,形成递归函数的链条;

  • 链条:最低层以上的柱子再次进行以上步骤,假设移动了最低层以上的圆盘,只剩下了最底层的那个圆盘。


count = 0

def hanoi(n: int, start: str, end: str, mid: str):

    global count  # 将count改为本module的全局变量

    # 从最下面的那个圆盘开始编写移动

    if n == 1:

        # 打印第一个圆盘的移动位置

        print('{}:{}->{}'.format(1, start, end))

        # 记录本次移动

        count += 1

    # 然后 是除了最下面圆盘之外的圆盘

    else:

        # 递归最底层以上圆盘

        hanoi(n - 1, start, mid, end)

        # 打印最底层以上圆盘的位置

        print('{}:{}->{}'.format(n, start, end))

        count += 1

        # 再次递归本次函数 通过对参数位置的改变,从而实现递归关系的链接

        # 现在的开始柱子是上一次的中介柱子,现在的目标柱子是上一次的开始柱子,中介柱子是上一次的目标柱子

        hanoi(n - 1, mid, end, start)

# 调用汉诺塔函数

hanoi(3, 'a', 'c', 'b')

print(count)

实现结果如下:

image-20210201153841038

以上可发现,最终通过7个步骤完成3个圆盘的汉诺塔游戏;

  1. 第一个圆盘,从a柱移动到b柱

  2. 第二个圆盘,从a柱移动到c柱

  3. 第一个圆盘,从b柱移动到c柱

  4. 第三个圆盘,从a柱移动到b柱

  5. 第一个圆盘,从c柱移动到a柱

  6. 第二个圆盘,从c柱移动到b柱

  7. 第一个圆盘,从a柱移动到b柱

动态展示如下:

3个圆盘的汉诺塔动态图

本项目说明

使用方法一:命令行运行


python hanoi.py [参数圆盘]

比如:


python hanoi.py 4

使用方法二:运行diaoyong_myhanoi文件调用函数

比如:


import myhanoi

myhanoi.hanoi(3, '开始', '中介', '目标')

小结

  1. 递归函数重在基例和链条的理解。基例不一定是最初的数值,在汉诺塔问题中,基例是其中的一个状态。

  2. 递归虽然简洁,但是在处理速度和理解上有些难,在编程时尽量少用,文科生只需看懂递归函数即可。

参考资料:

Leo_wlCnBlogs:汉诺塔问题.https://www.cnblogs.com/Leo_wl/p/3335388.html

菜鸟教程:Python 汉诺塔.https://www.runoob.com/w3cnote/python-tower.html

文字编辑:数据猿Riggle

首发平台:vx号:文科数据员

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351