Python零基础入门学习12:代码复用与函数递归

:本文所有代码均经过Python 3.7实际运行检验,保证其严谨性。

代码复用

代码复用是将代码当成资源进行抽象。

代码资源化:程序代码是一种用来表达计算的“资源”。

代码抽象化:使用函数等方法对代码赋予更高级别的定义。

函数和对象是代码复用的两种主要形式。

函数:将代码命名在代码层面建立了初步抽象。

对象:属性和方法<a>.<b>和<a>.<b>()在函数之上再次组织进行抽象。

模块化设计
所谓模块化设计,是通过函数或对象封装将程序划分为模块及模块间的表达,具体包括主程序、子程序和子程序间的关系。模块化设计遵循分而治之的原则。

紧耦合和松耦合

紧耦合:两个部分之间的交流很多,各自无法独立存在。

松耦合:两个部分之间的交流较少,各自可以独立存在。

模块内部,也就是函数内部,尽可能地让紧耦合多一些。

模块外部,也就是模块与模块之间,尽可能让松耦合多一些。

这些就是模块化设计的基本思路。

函数递归(Recursion)

递归是指函数定义中调用函数自身的方式。

递归的思想是将一个问题化成一个小的、简单的版本,即递归步骤。
继续简化问题,直至该问题简化到足够简单,可以直接解决。这叫基准条件base case。当回到base case时,循环就到了停止的条件,会停下来。
举例计算 a * b,将之用递归的思想来实现就是:

a * b = a; if b = 1 (基准条件base case)。

若b != 1,那么,就回到了a * b = a + a * (b - 1)(递归步骤recursion step)。

具体代码如下:

def recurMul(a, b):
    if b == 1:
        return a
    else:
        return a + recurMul(a, b - 1)

递归虽然不是for和while那样的循环,但可以事实上实现循环的效果;而循环终止的条件就是基准条件。

递归类似于数学中的归纳法,可以理解为数学归纳法在编程中的应用。

函数递归的应用之一:斐波那契数列问题

假设有一对刚出生的雌雄兔子,兔子从出生到成熟(能怀孕)需要1个月时间,然后开始交配,从交配到生下小兔子也需要1个月,假设每次每只雌兔都生一对雌雄兔子,每只雌兔从生完第一胎后,下个月还是会继续生一对雌雄兔子。假设兔子永远不死。

要解决的问题是,一年(12个月)之后,一共会有多少只雌兔?

解答:FIBONACCI斐波纳契的算法思路如下:

最开始(month 0):共有1只雌兔。

过了1个月(month 1):还是一共只有1只雌兔(开始怀孕)。

过了2个月(month 2):共2只雌兔,1只开始怀孕,1只刚出生。

过了3个月(month 3):共3只雌兔,2只开始怀孕,1只刚出生。

……

以此类推,过了n个月(month n)一共有雌兔的数量为:
females(n) = females(n - 1) +females(n - 2)。

这是因为,按照规律,过了n个月(month n)时,每一只活着的雌兔都会在month n时,生出1只雌兔;那些在month n时出生的新的雌兔子可以被添加到上个月活着的雌兔身上。所以,在month n时,雌兔子总数是 month n-2时活着的雌兔数量 — — 因为它们每一只都生出了一只新的后代 — — 加上month n-1时所有活着的雌兔数量。

如何用递归思想解决FIBONACCI斐波纳契问题
根据上面的思路算法探讨,来判定FIBONACCI斐波纳契问题的基准条件和递归步骤。

基准条件有2个:

-Females(0) = 1

-Females(1) = 1

递归步骤就是上面找出规律的计算公式:

females(n) = females(n - 1) + females(n - 2)

这样就可以构建递归函数了,代码如下:

def fib(x):
    if x == 0 or x == 1:   # base cases
        return 1
    else:
        return fib(x-1) + fib(x-2)    

print(fib(12))  # 12个月之后一共的雌兔的数量。

<<<233
函数递归的应用之二:汉诺塔问题

汉诺塔问题是由法国数学家Edouard Lucas于1883年根据传说提出来的。

传说在一个印度教寺庙里有三根柱子,其中一根从上向下套着64个由小到大的黄金盘片,僧侣们的任务就是把这一叠黄金盘从一根柱子搬到另一根。

注意,这个任务有两个限制规则:

规则1:一次只能搬一个盘子。

规则2:自始至终大盘子都不能叠在小盘子上,只能让小盘子叠在大盘子上。

解答:用递归的思想思考此问题,那么,n个盘可以分为1(基准条件)和n-1两个盘(n-1盘视为一个整体),再在n-1盘里面使用递归。

具体步骤为:
1)当有1个盘时,直接把这个盘从fr柱子放到to柱子上。代码如下:

def Towers(n, fr, to, spare): # 参数中,第1个是盘的总数,第2个是盘的出发柱子,第3个是盘的目标柱子,第4个是空闲柱子,这个3个柱子——出发柱子、目标柱子和空闲柱子,在盘的腾挪转移过程中是相对的,并非绝对的)

    if n == 1:
       printMove(fr, to)

2)当有n个盘时,从fr柱子(出发柱子)拿出最上面的n-1盘,放到spare柱子(目标柱子)上,此时to柱子就是空闲柱子。代码如下:

    else:
        Towers(n-1, fr, spare, to)

然后再把fr柱子里的最后1个盘放在to柱子上,此时spare柱子就成了空闲柱子。代码如下:

        Towers(1, fr, to, spare)

最后,把spare柱子(出发柱子)上的n-1盘,放到to柱子(目标柱子)上,此时fr柱子就成了空闲柱子了。因此代码如下:

        Towers(n-1, spare, to, fr)

具体代码实现如下:

#汉诺塔问题
count = 0
def hanoi(n, fr, to, spare):
    global count
    if n == 1:
        print("{}号盘片:从{}柱子搬到{}柱子。".format(1, fr, to))
        count += 1
    else:
        hanoi(n - 1, fr, spare, to)
        count += 1
        print("{}号盘片:从{}柱子搬到{}柱子。".format(n, fr, to))
        hanoi(n - 1, spare, to, fr)

hanoi(3, "A","B","C")  # 当柱子上的盘片为3时的情形。
print("整体的搬运次数为{}次。".format(count))
<<<
1号盘片:从A柱子搬到B柱子。
2号盘片:从A柱子搬到C柱子。
1号盘片:从B柱子搬到C柱子。
3号盘片:从A柱子搬到B柱子。
1号盘片:从C柱子搬到A柱子。
2号盘片:从C柱子搬到B柱子。
1号盘片:从A柱子搬到B柱子。
整体的搬运次数为7次。
<<<

由于递归的效率非常低,有大量的重复计算,所以上例中取盘片数量为3作为例子。事实上,按照上述算法,搬运盘片的次数的计算公式为2n-1次,3个盘片的搬运次数为23-1=7次。

汉诺塔原故事里还有一个细节,那就是,神的旨意说,一旦这些盘子完成迁移,寺庙将会坍塌,世界将会被毁灭。

神的旨意是正确的。

这是因为,要搬完64个盘片,按照计算公式2n-1计算,需要的移动次数是264-1=18446744073709551615。即使寺庙里有人能快到每秒搬动一次盘子,按一年365天、一天24小时计算,全部搬完也需要584942417355.072年,即超过5800亿年。到时地球早就被毁灭了,因为地球的寿命只剩下大约50亿年。

所以,若按照原题意取64个盘片的话,神的旨意说,一旦这些盘子完成迁移,寺庙将会坍塌,世界将会被毁灭。

To be continued.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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