递归算法学习

news2024/11/15 12:40:54

在这里插入图片描述

递归算法介绍

递归指的是函数或算法在执行过程中调用自身。在递归的过程中,程序会不断地将自身的执行过程压入调用栈中,直到满足某个条件结束递归调用并开始返回。递归算法常用于解决一些具有递归结构的问题,比如树、图、排序等。递归算法可以使代码更加简洁明了,但也需要注意递归深度、算法效率和内存占用等问题。

image-20230617201515398

通俗的说,递归就像是一个函数在执行时,需要重复调用自己来完成它的任务。这有点像一个人从一层楼爬到另一层楼,如果每层楼的高度一样,那么他就可以一直重复爬楼梯,直到到达目标楼层为止。但是,如果楼层高度不一样,那么他需要考虑更多的事情,这时他就需要仔细思考每一步,并把每一步都记录下来,以便后面使用。递归算法也是这样,每一次重复调用相当于在上一次调用的基础上再做一些事情,直到到达“楼顶”(即达成某个条件),然后再逐层返回。上面的图片来自于网络,非常友好的解释了这一算法,非常形象!

递归算法适用场景

递归算法通常适用于以下几种场景:

  1. 树形结构:树形结构是递归的典型应用场景之一。树是由节点和边组成的,每个节点可以有多个子节点,子节点又可以作为父节点继续分叉。例如二叉树、多叉树、字典树等,都是递归算法的经典应用场景。

  2. 排序算法:一些排序算法,例如快速排序、归并排序等,都可以使用递归算法来实现。这些排序算法都采用了分治法的思想,即将一个大问题分解为多个小问题并分别解决,然后将这些小问题的解合并起来得到整个问题的解。

  3. 动态规划算法:动态规划算法是一种常用的优化算法,它可以将大问题分解为小问题并分别解决,然后将这些小问题的解合并起来得到整个问题的解。在动态规划算法中,递归也是一种常用的解决方式。

总之,递归算法适用于那些具有递归结构的问题,可以将复杂问题分解为简单问题并分别解决,然后将这些简单问题的解合并起来得到复杂问题的解。

递归算法使用注意项

在使用递归算法的时候,需要特别注意以下几个方面:

  1. 递归深度:递归调用过多会导致调用栈溢出,因此需要控制递归深度,避免递归层数过深而导致程序崩溃。

  2. 算法效率:递归算法的时间复杂度有时候可能比较高,因此需要对算法进行优化,避免产生过多的计算,提高算法效率。

  3. 内存占用:递归算法会造成一定的内存开销,因为每一次递归调用都需要将方法的调用数据保存在栈中。如果递归调用次数过多,会导致内存占用过大,可能会导致内存溢出或程序崩溃。

  4. 边界条件:递归算法必须设置边界条件,以保证递归过程的正确性。边界条件是指确定递归何时终止的条件,通常是在递归到最小或最大问题实例时。

总之,使用递归算法需要谨慎,需要考虑递归深度、算法效率、内存占用和边界条件等问题,以保证算法的正确性和性能。

计算斐波那契数列(Fibonacci Sequence)

一个经典的递归算法例子是计算斐波那契数列(Fibonacci Sequence)。斐波那契数列是一个数列,其中每个数字是前两个数字之和。

以下是使用Python实现斐波那契数列的递归算法:

def fibonacci(n):
    if n <= 1:
        return n
    else:
        return (fibonacci(n-1) + fibonacci(n-2))

# 测试
n = 6
result = fibonacci(n)
print("斐波那契数列第", n, "项为:", result)

在这个例子中,fibonacci() 函数通过递归方式计算斐波那契数列的第 n 项。当 n<=1 时,直接返回 n
对于其他大于1的值,通过调用自身来计算前两个数列项的和,并返回结果。

以上代码输出示例:

斐波那契数列第 6 项为: 8

该递归算法简洁地实现了斐波那契数列的计算,但需要注意的是,随着 n 的增加,递归的层数也会相应增加,可能导致性能上的问题。在实际应用中,可以考虑使用迭代或其他优化方式来改进算法性能。

递归实现的求阶乘

下面是一个用递归实现的求阶乘的python函数:

def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)
result=factorial(5)
print("5的阶乘为:",result)
5的阶乘为: 120

在上面的代码中,我们定义了一个名为factorial的函数,它接受一个整数n作为输入。当n等于1时,返回1;否则,返回n与函数factorial(n-1)的乘积。这里,函数factorial反复调用自身来计算出n的阶乘。例如,当输入n=5时,函数factorial依次调用了factorial(4)、factorial(3)、factorial(2)、factorial(1),最后得到5 x 4 x 3 x 2 x 1 = 120,即5的阶乘。

递归算法遍历二叉树

img

二叉树是一种特殊的树型结构,它每个节点最多只有两个子节点,分别称为左子节点和右子节点。对于二叉树上的每个节点,它的左子树和右子树也都是一个二叉树。二叉树的节点可以是任意类型的数据,包括整数、浮点数、字符串、自定义对象等。

下面是一个二叉树的图例:

     5
    / \
   3   8
  / \   \
 1   4   9

在上面的二叉树中,根节点的值为5,左子树的节点1、3、4组成一棵二叉树,右子树的节点8、9组成另外一棵二叉树。

二叉树的一个重要应用是作为搜索树。搜索树是一种特殊的二叉树,它的每个节点的值都大于其左子节点的值,小于其右子节点的值。搜索树可以使用二叉查找算法进行快速的查询、插入和删除。另外,二叉树还可以用来表示表达式、构建哈夫曼树等。在计算机科学中,二叉树是一种非常重要的数据结构。

二叉树在计算机科学中有广泛的应用场景,以下是一些二叉树的使用场景:

  1. 搜索和排序:二叉搜索树是一种使用二叉树实现的查找和排序算法。二叉搜索树具有很高的查找和排序速度,因为每个节点都可以利用它的二叉树性质来缩小查找范围。

  2. 表达式树:二叉树可以用来表示算术表达式,这可以简化计算机的求值过程。例如,一棵表达式树的中序遍历结果就是树代表的表达式。

  3. 文件系统:许多操作系统使用二叉树来组织文件系统。目录树结构可以使用二叉树来实现,每个目录就是一个节点,每个目录都可以包含多个子目录或文件。

  4. 数据压缩:Huffman编码是一种基于二叉树的无损数据压缩算法。在编码和解码过程中,二叉树被用于表示字符编码和解码方式。

  5. 线段树:线段树是一种使用二叉树实现的数据结构,它可以有效地处理线段区间问题。例如,求解区间最小值、区间最大值、区间和等问题。

总之,二叉树在算法、数据结构、编译器、操作系统等领域都有广泛的应用,是计算机科学中非常基础和重要的数据结构之一。

下面是一个使用递归算法遍历二叉树的例子:

假设我们有一个二叉树的节点定义如下:

class TreeNode():
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

有了节点的定义之后,我们可以考虑使用递归算法实现二叉树的遍历。下面是三种遍历方式的具体实现:

  1. 前序遍历(Pre-order Traversal):先遍历根节点,然后遍历左子树,最后遍历右子树。
def pre_order_traversal(node):
    if node is None:
        return
    print(node.val)
    pre_order_traversal(node.left)
    pre_order_traversal(node.right)
  1. 中序遍历(In-order Traversal):先遍历左子树,然后遍历根节点,最后遍历右子树。
def in_order_traversal(node):
    if node is None:
        return
    in_order_traversal(node.left)
    print(node.val)
    in_order_traversal(node.right)
  1. 后序遍历(Post-order Traversal):先遍历左子树,然后遍历右子树,最后遍历根节点。
def post_order_traversal(node):
    if node is None:
        return
    post_order_traversal(node.left)
    post_order_traversal(node.right)
    print(node.val)

在上述三个函数中,都是使用递归的方式遍历二叉树。每次遍历时,都先检查当前节点是否为空,如果不为空,则分别调用递归函数遍历左子树和右子树,并输出当前节点的值。这样我们就可以通过递归实现二叉树的遍历了。

递归算法设计迷宫案例

下面是一个用递归算法解决迷宫问题的例子,假设我们已经有了一个 m m m n n n 列的迷宫,其中 0 0 0 表示通路, 1 1 1 表示障碍物, S S S 表示起点, G G G 表示终点,它们的定义如下:

maze = [
    [0, 1, 0, 0, 0, 1],
    [0, 1, 0, 1, 0, 1],
    [0, 0, 0, 0, 0, 0],
    [0, 1, 1, 1, 1, 0],
    [0, 0, 0, 0, 0, 0],
]

START_POS = (0, 0)  # 起点坐标
GOAL_POS = (4, 5)   # 终点坐标

要求我们编写递归函数 maze_solver(pos) ,用于求解从起点出发到达终点的一条通路,其中 pos 表示当前访问的位置的坐标 (row, col)。

def maze_solver(pos):
    # 边界条件
    if pos == GOAL_POS:  # 已经到达终点
        return True
    if not is_valid(pos):  # 当前位置无效
        return False
    if is_visited(pos):  # 当前位置已经被访问过了
        return False
    
    # 处理当前位置
    add_visited(pos)  # 标记当前位置已被访问
    
    # 递归访问上下左右四个方向
    if maze_solver((pos[0]-1, pos[1])):  # 上
        add_path(pos)
        return True
    elif maze_solver((pos[0]+1, pos[1])):  # 下
        add_path(pos)
        return True
    elif maze_solver((pos[0], pos[1]-1)):  # 左
        add_path(pos)
        return True
    elif maze_solver((pos[0], pos[1]+1)):  # 右
        add_path(pos)
        return True
   
    return False  # 无路可走的情况


# 工具函数:检查当前位置是否是通路
def is_valid(pos):
    i, j = pos
    if 0 <= i < len(maze) and 0 <= j < len(maze[0]) and maze[i][j] == 0:
        return True
    return False

# 工具函数:查找当前位置是否已经被访问过
visited = set() 

def is_visited(pos):
    return pos in visited

# 工具函数:将当前位置标记为已访问
def add_visited(pos):
    visited.add(pos)

# 工具函数:将路径添加到路线中
path = []

def add_path(pos):
    path.append(pos)

# 执行迷宫求解
maze_solver(START_POS)

# 输出结果
print(path)  # [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (3, 2), (3, 3), (3, 4), (4, 4), (4, 5)]

在上述代码中,我们使用了递归算法实现了从起点开始搜索迷宫通路的过程。在每个位置上,我们先检查当前位置是否有效,即当前位置是否越界或者是否是障碍物;如果当前位置有效,我们则将当前位置标记为已访问。接着我们递归访问当前位置的四周位置,如果有一条通路可以到达终点,我们则将当前位置加入路线中,并返回True。如果四周都无法到达终点,则返回False。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/657400.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.controller部署nova服务

nova 服务是 OpenStack service 计算服务&#xff0c;负责维护和管理云环境的计算资源&#xff1b; 例如&#xff1a; 接收客户端请求需要的计算资源&#xff1b; 确定实例在哪个物理机上创建&#xff1b; 通过虚机化的方式将实例启动运行等工作。 controller节点 在安装和配…

JAVA为什么要面向对象

JAVA是一个面向对象的语言 ok&#xff0c;我们开始&#xff0c;用了那么久的java&#xff0c;看了那么多代码&#xff0c;你是否懂得了面向对象&#xff0c;今天我们的第一个问题就是&#xff0c;为什么java要面向对象&#xff0c;要解释为啥要面向对象&#xff0c;我们首先要…

Python selenium自动化测试模型图解

1、线性测试 优势&#xff1a;每一个脚本都是完整独立的&#xff0c;每一个脚本对应一个测试用例 缺点&#xff1a;开发成本高&#xff0c;会有重复操作重复脚本&#xff1b;维护成本也高&#xff0c;修改重复操作的脚本时&#xff0c;要逐一进行修改。 2、模块化驱动测试 …

2023年计算机专业毕业实习报告最新

2023年计算机专业毕业实习报告最新篇1 一、实习基本情况 按照学校对毕业生的要求&#xff0c;为毕业后的工作和谋职打下良好的基础。我于X年X月来到山西柳林汇丰兴业同德焦煤有限公司进行为期X个月的实习。毕业实习让我们想起那句老话&#xff1a;“让学生赢在起跑线上。”在学…

验证性实验 - 线性回归

练习1&#xff1a;线性回归 介绍 在本练习中&#xff0c;您将实现线性回归并了解其在数据上的工作原理。 在开始练习前&#xff0c;需要下载如下的文件进行数据上传&#xff1a; ex1data1.txt -单变量的线性回归数据集ex1data2.txt -多变量的线性回归数据集 在整个练习中&a…

马斯克撕下美国的遮羞布,美企纷纷背刺,外媒:可怕的还在后面

马斯克访华造成的影响还在持续&#xff0c;随着更多美国企业家访华以及表明态度&#xff0c;可以说他们正撕下美国的遮羞布&#xff0c;今天的美国其实早已背离了当初他们所宣扬的价值&#xff0c;凸显出外强中干的本质。 二.美国企业家纷纷访华撕下美国遮羞布 美国一直都标榜贸…

某购房通小程序解密分析【2023.6.17】

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 主要对小程序返回的加密结果进行解密的分析过程只…

如何在编程中中实现负载均衡和容错处理

什么是容错 容错是指系统&#xff08;计算机、网络、云集群等&#xff09;在其一个或多个组件发生故障时继续运行而不会中断的能力。 创建容错系统的目的是防止由单点故障引起的中断&#xff0c;确保任务关键型应用程序或系统的高可用性和业务连续性。 容错系统使用备份组件…

DAY26:回溯算法(一):回溯算法理论

课程链接&#xff1a;https://www.bilibili.com/video/BV1cy4y167mM/?spm_id_from333.788 什么是回溯法 回溯法 - OI Wiki (oi-wiki.org) 回溯法是一种经常被用在 深度优先搜索&#xff08;DFS&#xff09; 和 广度优先搜索&#xff08;BFS&#xff09; 的技巧。 其本质是…

Elasticsearch 基本使用(一)写入数据

写入数据 查询索引状态写入一条数据查询数据按id查询一条 类比 getById不按id查 写入官方测试数据 查询索引状态 GET _cat/indices写入一条数据 PUT/POST my_index/_doc/1 {"k": "test key" }my_index&#xff1a;索引名 _doc&#xff1a;文档类型&#…

css基础知识三:说说em/px/rem/vh/vw的区别?

一、介绍 传统的项目开发中&#xff0c;我们只会用到px、%、em这几个单位&#xff0c;它可以适用于大部分的项目开发&#xff0c;且拥有比较良好的兼容性 从CSS3开始&#xff0c;浏览器对计量单位的支持又提升到了另外一个境界&#xff0c;新增了rem、vh、vw、vm等一些新的计量…

2023年网络安全竞赛——网页渗透

网页渗透 任务环境说明:  服务器场景:Server2120  服务器场景操作系统:未知(封闭靶机)  用户名:未知 密码:未知 访问服务器的网站主页,猜测后台数据库中本网页中应用的库名称长度,将长度作为flag提交; 通过扫描发现靶机开放80端口,直接访问80 尝试输入一个1,…

Web安全信息收集之CMS指纹识别

1、CMS指纹识别 CMS(内容管理系统),又称整站系统或文章系统网站内容管理。用户只需要下载对应的CMS软 件包,部署搭建,就可以直接利用CMS,简单方便。但是各种CMS都具有其独特的结构命名规则和定 的文件内容,因此可以利用这些内容来获取CMS站点的具体软件CMS与版本 常见CMs: …

软件管理Linux

1. 获取程序包的途径 系统发行版的光盘或官方的服务器 http://mirrors.aliyun.comhttp://mirrors.sohu.comhttp://mirrors.163.com 项目官方站点第三方组织 Fedora-EPEL&#xff08;推荐&#xff09;搜索引擎&#xff1a; http://pkgs.org http://rpmfind.net http://rpm.pbon…

数据库第十章(数据库恢复技术)十一章(并发控制)

目录 1.事务 2.并发控制 1.事务 事务的特点&#xff1a;ACID 原子性 atom 一致性 consistent 隔离性 isolation 持久性 durable 故障的种类 1.事务内部故障 措施&#xff1a;采取redo重做和undo撤销技术 2.系统故障DBMS 措施&#xff1a;重启 3.介质故障 硬件损坏 4.计…

msvcr110.dll丢失的解决方法-dll一键下载修复

我们在运行软件程序或者游戏的时候&#xff0c;如果程序提示“无法启动此程序&#xff0c;因为计算机中丢失msvcr110.dll。尝试重新安装该程序以解决此问题”&#xff0c;如果说明您电脑系统中缺少或者未注册msvcr110.dll这个运行库文件&#xff0c;那么我们要如何解决这个问题…

大学生简历信息填写模板

大学生简历信息填写模板篇1 姓名&#xff1a;__性别&#xff1a;_年龄&#xff1a;22健康状况&#xff1a;良好 籍贯&#xff1a;__家庭背景&#xff1a;职工家庭 所学专业&#xff1a;市场营销学历&#xff1a;本科(在读) 参业意向&#xff1a;可从事文秘工作、贸易、产品营销…

pytorch神经网络及训练(一)

pytorch神经网络及训练&#xff08;一&#xff09; 随机梯度下降算法 随机梯度下降算法&#xff08;SGD&#xff09;是对梯度下降算法的一种改进。 直观上SG的方法可能效率上更优。考虑这样一个情况&#xff0c;我们的训练数据集合 是由小的数据 集合复制10份得到的。此时&…

Java代码规范的重要性

目录 1 为什么需要代码规范1.1 不规范的案例1.1.1 就因为忘记加个分号&#xff0c;整个程序都崩溃了1.1.2 我为什么没写注释&#xff1f;1.1.3 谁动了我的代码&#xff1f;1.1.4 半小时写的代码&#xff0c;花两个小时调试 1.2 代码编写1.3 在项目架构1.4 数据库设计1.5 编写文…

openpnp - 软件版本的更新记录(机器翻译)

文章目录 openpnp - 软件版本的更新记录(机器翻译)概述openpnp更新历史记录机翻了一个版本, 大概齐参考一下.END openpnp - 软件版本的更新记录(机器翻译) 概述 卡在底部相机矫正上, 底部相机的硬件安装已经很精确了, 基本能排除是硬件问题. 现在问题定位, 大概率是openpnp软…