代码复用与函数递归

news/2024/7/8 3:11:04

代码复用与模块化设计:

代码复用:

把代码当成资源进行抽象

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

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

代码复用:同一份代码在需要时可以被重复使用,而代码复用是需要我们将代码进行抽象才能达到的效果。

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

函数:将代码命名(在代码层面(对函数的或者对功能的一种抽象)建立了初步抽象)函数是对代码的一种抽象

对象:属性和方法(将一组变量或一组函数在基础之上进一步进行抽象)

对象的格式如下:<a>.<b>和<a>.<b>() 在函数之上对程序的再次组织进行抽象,实际上是一种面向对象的程序设计方法

从函数到对象,他们的抽象级别在不断提高。

函数和对象是实现代码复用的方法,是对代码进行抽象的不同级别。

对于代码复用,我们可以使用函数或对象通过封装将功能进一步的抽象,可以通过这种高层次的抽象,来完成一些更高层次的功能设计。

模块化设计:

在代码复用的基础上,程序员可以开展模块化设计,模块化设计基于一种逻辑的设计思维,叫做分而治之。

分而治之:使用函数或对象通过封装将程序划分为模块及模块间的表达

具体包括:主程序(模块与模块之间的关系)、子程序(模块)和子程序间关系

分而治之的思想是模块化设计的核心

分而治之:模块化设计是一种分而治之、分层抽象、体系化的设计思想

模块化设计:紧耦合:两个部分之间交流很多,无法独立存在

松耦合:两个部分之间交流很少,可以独立存在。他们之间有非常清晰简单的接口

我们通过函数来将一段代码与代码的其他部分分开,那么对于函数的输入参数和返回值就是这段函数与其他代码之间的交流通道,这样的交流通道越少越清晰,即所定义的函数模块越少,对于实现复杂的功能,对于定义的函数的复用可能性就会越高。

模块内部紧耦合,模块之间松耦合,他们之间可以通过局部变量可以进行大量的数据传输,但是在模块之间,函数与函数之间要尽可能的减少他们的传递参数和返回值,让他们之间以松耦合的形式进行组织,这样每一个函数才有可能被更多的函数所调用,他的代码才可能被更多的复用。

函数递归:

什么是递归呢?在函数定义中,调用函数自身的方式就是递归。

求解n的阶乘的时候,当n=0的时候,阶乘为1.

当求取其他值的阶乘的时候,阶乘为n(n-1)!

n!的定义也是一种递归形式,即第n的阶乘的值与n-1的阶乘值之间存在了一种递归和递进的关系。这就是一种递归的表达。

递归的定义中有两个关键的特性,即链条和基例。

链条:计算过程存在递归有序的链条关系。

比如n!=n(n-1)!,n!与(n-1)!就构成了递归链条

基例:存在一个或多个不需要再次递归的基例

比如当n=0时,我们定义它的值为1,这就是一种基例,它与其它的值之间并不存在递归关系,它已经是递归的最末端。

没有链条的程序不是递归

没有基例的程序也构不成递归。

类似数学归纳法:证明一个定理成立的时候,一般我们采用数学归纳法可以这样证明

首先我们证明当n取第一个值n0时命题成立,假设当nk时命题成立,证明当n=nk+1时命题也成立,如果这两个步骤都是对的,我们就能证明某一个命题成立

递归是数学归纳法思维的编程体现。

函数递归的调用过程:

递归的实现:

求解n的阶乘的时候,当n=0的时候,阶乘为1.

当求取其他值的阶乘的时候,阶乘为n(n-1)!

递归函数在定义的时候,要满足两个基本条件:一个是递归公式,另一个是边界条件。其中,递归公式是求解原问题或相似的子问题的结构;边界条件是最小化的子问题,也是递归终止的条件。

递归函数的执行可以分为以下两个阶段
(1)递推:递归本次的执行都基于上一次的运算结果

(2)回溯:遇到终止条件时,则沿着递推往回一级一级地把值返回来。

递归函数的一般定义格式如下所示:

def 函数名([参数列表]):

if  边界条件:

return 结果

else:

return 递归公式

我们通过递归进行该代码的编写:

代码如下所示:

def fact(n):
    if n==0:
          return 1
    else:
          return n*fact(n-1)
n=eval(input("请输入一个整数:"))
result=fact(n)
print("n!={}".format(result))

运行界面如下:

我们计算3的阶乘,当计算机进行函数的调用的时候,先判断此时n的值与0不相同,即进行调用fact(2),此时计算机分配了一段内存,分配计算资源计算他的值,我们在进行判断,此时n的值为2,与0不同,继续调用fact(1),此时函数的n与1不同,继续调用fact(0),此时n的值与0相同,返回1,然后进行回溯,将结果一级一级往回返回。即fact(1)=n*fact(0)=1*1=1,fact(2)=n*fact(1)=2*1=2,

fact(3)=n*fact(2)=3*2=6,即结果为6。将结果进行输出。

当我们使用递归函数时,我们要包含一下结构:

函数+分支语句

递归本身就是一个函数,需要函数定义方式描述

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

基例和链条,分别编写对应代码

实例一:字符串反转:

将字符串s反转后输出:

在字符串里面我们已经学过,s[::-1],实现字符串反转,从最后面进行逐一的取出。

s[M:N],M缺失,表示从开头到N前面的那一个数为止。

N缺失,表示从M开始到结尾。

具体详细内容可以看此篇字符串详解的博客。http://javascript:;

函数递归需要:

函数+分支结构

递归链条

递归基例

代码示例如下:

def rvs(s):
    if s=="":
        return s
    else:
        return rvs(s[1:])+s[0]
s=input("请输入字符串:")
print(rvs(s))

运行界面如下:

 通过代码我们可知运行过程如下所示:

我们调用函数rvs(s),首先判断是否为空,不为空,我们调用rvs(gfypl),再次进行判断,仍不为空,继续调用rvs(fypl),再次判断,不为空,继续调用rvs(ypl),再次进行判断,仍不为空,继续调用rvs(pl),再次判断,不为空,继续调用rvs(l),再次进行判断,仍不为空,继续调用rvs(),再次判断,为空,我们再将结果依次返回,将rvs()返回,将rvs(l)返回,将rvs(lp)返回,将rvs(lpy)返回,将rvs(lpyf)返回,将rvs(lpyfg)返回后,再将原字符串的第一个字符加到最后及实现了字符串的反转。

实例二:斐波那契数列:

一个经典数列:

F(n)=1,n=1

F(n)=1,n=2

F(n)=F(n-1)+F(n-2),n=其他

代码示例如下:

def f(n):
    if n==1 or n==2:
        return 1
    else:
       return f(n-1)+f(n-2)
n=eval(input("请输入整数:"))
print(f(n))

运行界面如下:

我们通过调用函数,先进行条件判断,n=5,不符合n==1或n==2,我们进行调用f(4)+f(3),我们分别分配两个新的内存去调用f(4)和f(3),

调用f(4)时,我们分配一个新的内存进行计算,进行判断条件,不符合,我们调用f(3)+f(2),我们再分配两个新的内存,进行分别调用f(3)和f(2),调用f(3),判断条件不符合,我们调用f(2)+f(1)条件不符合,我们再进行调用f(2)和f(1),此时条件符合,依次往上返回结果,f(2)+f(1)=2,f(3)+f(2)=3,所以f(4)=3.通过相同的思路,我们求解f(3),

调用f(3)时,我们分配一个新的内存进行计算,进行判断条件,不符合,我们调用f(2)+f(1),此时条件符合,依次往上返回结果,f(2)+f(1)=2,即f(3)=2,两者相加即为5.

实例三:汉诺塔问题:

有三根柱子,其中一个柱子上摆放有从上到下将圆盘从小到大摆放,其中一根柱子为过度柱子,另一个柱子为目标柱子,将柱子上的圆盘放到目标柱子上,而且大圆盘不能放到小圆盘上,在移动过程中,一次只能移动一个柱子。如何移动我们通过递归过程进行解决:

count=0
def hanoi(n,src,dst,mid):  #n个圆盘,src为放置圆盘的圆柱,dst为目标圆盘,mid为过渡圆盘。
    global count
    if n==1:
       print("{}:{}->{}".format(1,src,dst))
       count+=1
    else:
       hanoi(n-1,src,mid,dst)    #将放置圆盘的柱子通过过渡圆盘放到目标圆盘
       print("{}:{}->{}".format(n,src,dst))
       count+=1
       hanoi(n-1,mid,dst,src)     #将过渡圆盘通过目标圆盘放到初始圆盘的柱子
hanoi(3,'A','C','B')   #A为初始圆盘,c为目标圆盘,B为过渡圆盘。
print(count)

运行界面如图:

通过程序运行结果我们得知,先将一个圆盘移动到目标圆盘,再将另一个圆盘移动到过渡圆盘,再将,在从目标圆盘放到过渡圆盘,再将初始圆盘的第三个放到目标圆盘,再将过度圆盘放到初始圆盘,将放到过度圆盘的第二个放到目标圆盘,最后从初始圆盘将最小的放到目标圆盘。最后成功计算出目标顺序。


http://www.niftyadmin.cn/n/4083971.html

相关文章

前端框架Layui的使用讲解(Layui搭建登录注册页面)

目录 一、前言 1.什么是Layui 2.Layui的背景 3.为什么要使用Layui 4.Layui的模块化 二、Layui使用讲解 1.初识Layui 2.搭建登录页面 静态效果图​ 封装引入文件页面&#xff08;公用页面&#xff09; jsp页面搭建 userDao编写 Servlet页面编写 xml文件配置 3.搭…

大数据处理的关键架构层

大数据处理的关键架构层 文件系统层&#xff1a;在这一层里&#xff0c;分布式文件系统需具备存储管理、容错处理、高可扩展性、高可靠性和高可用性等特性。 数据存储层&#xff1a;由于目前采集到的数据&#xff0c;十之有七八为非结构化和半结构化数据&#xff0c;数据的表…

PyInstaller库基本介绍

将.py源代码转换成无需源代码的可执行文件 .py文件通过PyInstaller转换为Windows系统可以直接运行的(.exe文件&#xff09;&#xff0c;Linux系统&#xff0c;Mac OS X系统可以运行的。 将py扩展名的任何python的源代码转变成Windows、Linux系统&#xff0c;Mac OS X系统的可…

科赫雪花小包裹实例详解

高大上的分形几何 分形几何是一种迭代的几何图形&#xff0c;广泛存在于自然界中&#xff08;树叶&#xff0c;菜花&#xff09;&#xff08;这个东西的整体与他的局部具有很相似的特点&#xff09; 分形几何中有一种特殊的曲线叫做科赫曲线&#xff0c;也叫雪花曲线 科赫曲…

Step by Step SharePoint 2010 Install RTM

http://blogs.architectingconnectedsystems.com/blogs/cjg/archive/2010/05/27/Step-by-Step-SharePoint-2010-Instal-RTM.aspx转载于:https://www.cnblogs.com/joe-yang/archive/2010/06/05/1752379.html

组合数据类型(集合)

组合数据类型包括集合类型及操作、序列类型及操作&#xff08;元组类型和列表类型&#xff09;、字典类型及操作 集合是多个元素的无序组合 集合类型与数学中的集合概念一致&#xff0c;数学中的集合是指具有某种特定性质的对象汇总而成的集体&#xff0c;其中组成集合的对象…

浏览器本身自带的下载管理器和专用下载软件的区别

最近&#xff0c;需下载Solaris操作系统的iso文件&#xff0c;我先后使用了好几个浏览器来下载该文件&#xff0c;最后都会在下载的中途停止&#xff0c;显示的细致速度为0。我之所以没有采用专用的下载软件&#xff0c;如FlashGet等下载&#xff0c;是因为我浏览器本身自带的下…

数据存储层

宽泛地讲&#xff0c;据对一致性&#xff08;consistency&#xff09;要求的强弱不同&#xff0c;分布式数据存储策略&#xff0c;可分为ACID和BASE两大阵营。ACID是指数据库事务具有的四个特性&#xff1a;原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consis…