前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我用 Python 面向对象做算法题,她说要先给兔子找上对象

我用 Python 面向对象做算法题,她说要先给兔子找上对象

作者头像
TTTEED
发布2020-07-09 14:50:52
4400
发布2020-07-09 14:50:52
举报

休假回来发现自己在刷题小组进度滞后,昨晚想着刷几道题赶赶进度,其中有一道还挺有意思:

刚用斐波那契数列的思路分析完,想再分析下附加题中面向对象的方法,恰好 真·对象 发来了信息,并产生了标题中描述的对话。

她:“不懂什么是面向对象”

我:“就是面对着你”

她:“那得先给兔子找上对象,不止是个数学问题”

我:“……”

我:“人家就是一对兔子”

她:“哦,生的还得是一对兄妹,然后近亲结婚是么”

我:“……”

值得表扬的是,今天她还能记起昨天那问题,我也顺便就着例子做了番讲解,毕竟她也不懂编程,只聊了下大致思路。

经过一番讲解,真·对象 表示能理解了、而且非常透彻!

而我此刻立马联想到一张表情图:


好,让我们回到那个生兔子的算法题,同时也正好拿这个题目来说道说道“面向过程”和“面向对象”的概念。

#面向过程

如果没有接触过斐波那契数列,初遇这题会一脸懵。

斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。 百度百科-斐波那契数列

有了斐波那契数列概念后,计算兔子数量也就转化成了计算数列中第 n 项的问题。相应地,我们的思路也是如何通过代码计算该数列中的第 n 项,明显的是以计算过程为中心,也就是所谓的“面向过程”。

Python 代码如何实现该过程呢?我们可以定义个函数,n 代表兔子问题中的月份或者兔子数列中的第 n 项,n < 3 时结果是 1,n >= 3 之后就需要通过前两项相加来不断产生后续的结果、故通过一个 for 循环来执行该递推过程。

代码语言:javascript
复制
def get_result(n):
    if n<3:
        result = 1
    else:
        x = 1
        y = 1
        for i in range(n-2):
            x,y = y,x+y
        result = y
    return result
# 获取第 10 个月的兔子数量;获取兔子数列的第 10 项
result = get_result(10)
print(result)

通过运行代码,第 10 个月兔子数量为 55 对。

#面向对象

首先是面向对象的概念:

面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。 百度百科-面向对象

正如我们所知,Python 是一门面向对象的编程语言,其中通过 Class 类来描述具有相同的属性和方法的对象的集合,而对象也就是类的实例。

继续拿兔子说事,如果尝试按照时间轴去计算兔子数量其实比较难整理,不妨换个角度,我们把一对兔子封装成一个“类”,这样题目中的每对兔子就都成了这个兔子“类”的实例,而且每一对兔子的属性和功能都是相同的:它们都可以拥有数量的属性,也都可以具有繁殖的功能,唯一的区别就是其“出生时间”不同,也就是对应的时间 n 不同。

将兔子对转化成具体对象后,我们想获取的是兔子数目,那么就可以给兔子实例添加一个变量 count 用来统计数目。对每对兔子这个对象来说,它所关联的数量是它自身 1 对 和所有兔宝宝数量的总和。而其兔宝宝这个对象是每个月都会产生,且该兔宝宝数量又和兔孙孙的数量有关……这样,我们通过定义“类”,变相地规定好了所有兔子对象的行为和属性。

最终我们只要给定时间,便可通过兔子对象的数量属性获取到结果了~

代码语言:javascript
复制
# 面向对象编程解决兔子问题
# python 中通过 class 这个类来定义对象,我们给定义的对象取名 rabbit_pair (兔子对)
class rabbit_pair:
    # def 是用来定义这个对象能力的,首先通过 __init__ 给兔子定义数量标签 count 和 繁殖能力 product
    def __init__(self,month):
        self.count = 1
        self.product(month)
    # 繁殖能力要具体表明,是和时间 month 相关的
    def product(self,month):
        # 当 月数大于 2 时,就会繁殖
        while month>2:
            # 繁殖出的小兔子也是同样的兔子对象,区别是它所经历的时间比父母要少 2 个月,所以时间 -2
            child = rabbit_pair(month-2)
            # 繁殖后,兔子对象数量标签要把繁殖出的小兔子数量标签数目也给加进来
            self.count += child.count
            # 通过月数控制,来模拟整个时间轴上兔子对象的繁殖与数量变化
            month -= 1

# 把自己定义成经历 10 个月的兔子对象的实例
ted_mia = rabbit_pair(10)
# 获取兔子对象的数量标签
result = ted_mia.count
print(result)

通过运行代码,结果也为 55,附加题搞定~!

但是很遗憾,这个思路表面上是用对象来定义兔子,实际仍是递归思路去计算兔子数量,算不得真·面向对象。

#真·面向对象

原本文章到此是结束了的,但我因为自身编程很少用“类”和面向对象的思路去思考问题,为了保险,专门请教了下 Crossin 先生,还好有这么一问,不然还真的犯错了!

让我们按照正确的面向对象理念重新理一下思路:

仍旧是定义兔子“类”,每一对兔子都是该兔子类的实例。兔子本身并不知道其它兔子数量,所以我们不再引入数量属性。每个兔子随着时间变化自己会年龄增长,年龄达到 3 个月就会繁殖兔崽子。所以,我们要为兔子“类”定义“年龄”属性和“繁殖”的方法;同时,也要定义一个“生长”的方法来控制年龄。(当然,将生长和繁殖定义到同一个方法中更省事)

这样,我们的兔子类便定义好了。接下来要做的是,随着时间变量的变化,我们来来让兔子对象们来生长和繁殖。

至于如何统计数量,我们可以为其建立个“族谱”,也就是所有兔子的列表,只要生成了新的兔子实例,便将其纳入列表中,最终便可以根据该列表长度获取兔子家族的数量了。

修改后的真·面向对象思路代码如下:

代码语言:javascript
复制
# 真·面向对象思路解决兔子问题
# 定义兔子类
class Rabbit:
    # 通过 __init__ 构造方法为之后生成的兔子实例添加年龄变量
    def __init__(self):
        self.age = 0
    # 兔子生长通过 grow 方法来控制年龄生长
    def grow(self):
        self.age += 1
    # 兔子生育通过 product 方法来产生新的兔子实例    
    def product(self):
        # 只有年龄大于 2 个月,才可以产生兔崽子
        if self.age>2:
            return Rabbit()
        else:
            return None


month = 10
# 为兔子家族建立列表(可以理解为族谱)
family = []

# 第一对兔子是祖先
ted_mia = Rabbit()
# 先将兔祖先纳入族谱
family.append(ted_mia)

# 通过 for 循环控制时间流转
for i in range(month):
    # 时间长河中,族谱中的每一对兔子都会生长、繁殖
    for member in family:
        # 兔子生长
        member.grow()
        # 兔子繁殖
        child = member.product()
        # 如果产生了兔崽子,继续纳入族谱
        if child:
            family.append(child)

# 最终,兔子总数即其族谱中成员个数,也就是列表长度
result = len(family)
print(result)

经过运行,代码结果仍是 55,问题算是圆满解决了。

还好自己在发文之前咨询了下 Crossin 先生,才有了此番修正,也加深了对面向对象编程的理解。

当我将这番修改转发给 真·对象 时,终于,她,蒙圈了。。

从面向真·对象,到真·面向对象解决问题,今天也算收获不小。

以上,感谢阅读~!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TTTEED 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档