在那些场景下可能会用到递归?递归的缺点?

news/2025/1/12 22:46:57/文章来源:https://www.cnblogs.com/chhblogs/p/18667525

一、递归的应用场景
(一)树形结构相关问题
文件系统遍历
在计算机的文件系统中,目录和文件构成了一棵树。例如,一个根目录下有多个子目录,每个子目录又可以包含更多的子目录和文件。递归可以很好地遍历这种结构。以遍历一个文件夹中的所有文件为例,算法可以先处理根目录下的文件,然后对每个子目录递归调用遍历函数。比如在Python中,可以使用递归函数来遍历:

def traverse_directory(directory):
for item in os.listdir(directory):
item_path = os.path.join(directory, item)
if os.path.isfile(item_path):
print(item_path)
elif os.path.isdir(item_path):
traverse_directory(item_path)
这段代码会先列出当前目录下的所有文件和文件夹,如果遇到文件夹就递归调用自身,直到遍历完所有文件夹中的文件。
  • 组织架构查询
    • 在企业组织架构中,员工和部门也形成了树状结构。比如要查询某个员工的所有下属,可以使用递归。假设每个员工对象有一个属性是其直接下属的列表,从一个员工开始,先获取其直接下属,然后对每个下属递归查询其下属。例如在Java中:
public class Employee {private String name;private List<Employee> subordinates;public List<Employee> getAllSubordinates() {List<Employee> allSubordinates = new ArrayList<>();for (Employee subordinate : subordinates) {allSubordinates.add(subordinate);allSubordinates.addAll(subordinate.getAllSubordinates());}return allSubordinates;}
}

这样就可以通过递归获取一个员工的所有下属,包括间接下属。
(二)分治算法
快速排序
快速排序是一种经典的分治算法。它的基本思想是选择一个基准元素,将数组分为两部分,左边部分的元素都小于等于基准元素,右边部分的元素都大于等于基准元素。然后对左右两部分递归进行快速排序。例如,对一个整数数组进行快速排序:

def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
这里先通过基准元素将数组划分,然后对划分后的子数组递归调用快速排序函数,最终得到有序数组。
  • 归并排序
    • 归并排序也是分治算法的一种。它将数组不断分成两半,直到每个子数组只有一个元素(或者为空),然后将这些子数组合并成有序数组。在合并过程中,递归地将两个有序子数组合并成一个有序数组。例如:
def merge_sort(arr):if len(arr) <= 1:return arrmid = len(arr) // 2left = merge_sort(arr[:mid])right = merge_sort(arr[mid:])return merge(left, right)def merge(left, right):result = []while left and right:if left[0] <= right[0]:result.append(left.pop(0))else:result.append(right.pop(0))result.extend(left)result.extend(right)return result

先通过递归将数组分解,再通过递归合并有序子数组。
(三)组合与排列问题
生成排列
当需要生成一个集合的所有排列时,递归是一种很自然的方法。例如,要生成集合{1, 2, 3}的所有排列。可以先固定第一个元素为1,然后递归生成剩余元素{2, 3}的排列;再固定第一个元素为2,递归生成剩余元素{1, 3}的排列,以此类推。在Python中可以这样实现:

def permute(nums):
result = []
if len(nums) == 1:
return [nums]
for i in range(len(nums)):
current_num = nums[i]
remaining_nums = nums[:i] + nums[i + 1:]
for perm in permute(remaining_nums):
result.append([current_num] + perm)
return result
这样就可以得到集合的所有排列。
  • 组合问题
    • 比如从n个元素中选择k个元素的所有组合。可以使用递归,先选择一个元素,然后从剩下的元素中递归选择k - 1个元素。以从集合{1, 2, 3, 4}中选择2个元素为例:
def combine(n, k):def backtrack(start, path):if len(path) == k:result.append(path[:])returnfor i in range(start, n + 1):path.append(i)backtrack(i + 1, path)path.pop()result = []backtrack(1, [])return result

这段代码通过递归生成了所有可能的组合。
二、递归的缺点
(一)栈溢出
递归函数每次调用自身时,都会在调用栈上创建一个新的栈帧(frame)。栈帧用于存储函数的局部变量、参数等信息。如果递归的深度过大,就会消耗大量的栈空间。当栈空间被耗尽时,就会发生栈溢出错误。例如,在计算一个非常大的数的阶乘时(如10000的阶乘),如果不使用尾递归优化等方法,很容易导致栈溢出。因为每次递归调用都要保存当前的乘积结果等信息,随着递归深度的增加,栈空间被迅速占用。
(二)重复计算
在一些递归实现中,可能会出现对相同子问题的多次计算。以斐波那契数列为例,用简单的递归方法计算第n项:

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

当计算fibonacci(5)时,会计算fibonacci(4)fibonacci(3),而在计算fibonacci(4)时又会计算fibonacci(3)fibonacci(2)fibonacci(3)就被计算了两次。随着n的增大,重复计算的次数会呈指数级增长,这使得递归算法的效率非常低。`

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型AI应用场景及产品汇总(持续更新)

一、文生图 1. Napkin AINapkin AI 可以基于输入的文本生成各种图示,例如流程图、逻辑关系图等等。https://app.napkin.ai/

大模型AI应用场景汇总(持续更新)

一、文生图 1. Napkin AINapkin AI 可以基于输入的文本生成各种图示,例如流程图、逻辑关系图等等。https://app.napkin.ai/

G1原理—5.G1垃圾回收过程之Mixed GC

大纲 1.Mixed GC混合回收是什么 2.YGC可作为Mixed GC的初始标记阶段 3.Mixed GC并发标记算法详解(一) 4.Mixed GC并发标记算法详解(二) 5.Mixed GC并发标记算法详解(三) 6.并发标记的三色标记法 7.三色标记法如何解决错标漏标问题 8.SATB如何解决错标漏标问题 9.重新梳理Mixed …

AlexNet文献阅读与代码实现

目录AlexNet文献阅读与代码实现文献内容介绍代码实现内容总结 AlexNet文献阅读与代码实现前言:笔者目前研一,刚开始入门深度学习,所以想记录一下自己学习的过程,接下来的时间里,我会定期阅读深度学习领域的经典文献,并尝试用代码实现它们,也欢迎大家积极评论。注:博客本…

c语言的基本类型及输入输出占位符

基本类型 c语言的基本类型:int 【long、short、unsigned、signed(c90)】、char、float、double、_Bool【布尔值】、_complex、_Imaginary【复数和虚数】 输入输出 printf标志字符标志 含义- 转换的结果在字段内左对齐+ 有符号的转换结果总是以+或者-开始空格 如果有符号转换的…

LeetCode:65.有效数字

LeetCode:65.有效数字解题步骤构建一个表示状态的图。遍历字符串,并沿着图走,如果到了某个节点无路可走就返false。遍历结束,如走到3/5/6,就返回true,否则返回false。 extend 2 8 10 16进制 /*** 检查一个字符串是否可以表示为一个有效的数字* @param {string} s - 待检查的…

vs2019项目报错:文件中的类都不能进行设计,解决办法_无法设计基类system.void

文件中的类都不能进行设计,因此未能为该文件显示设计器。设计器检查出文件中有以下类: Form1 --- 无法设计基类“System.Void”。 出现上述错误,解决办法如下: 关闭所有设计窗口(例如form1.cs(设计)),菜单栏生成,清理解决方案,关闭vs2022,重新启动vs2022打开你的项目…

关于VSCode的c/c++环境配置

适用于Windows的VSCode的c/c++环境配置c/c++环境配置写给 初学C/C++的 保姆级 VSCode环境配置第一步 下载VScode 找到官网点下载就好啦下载安装完成之后,启动!点击左侧“拓展”图标下载中文拓展安装好后重启 别关 留着备用 第二步 下载c/c++编译器 这里我使用MinGw实际上 Mi…

G75 拉插 CF622F The Sum of the k-th Powers

视频链接: The Sum of the k-th Powers - 洛谷 | 计算机科学教育新生态// 拉插 O(klogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std;#define LL long long const int N=1e6+10,mod=1e9+7; int n,k; LL ml[N],mr…

Cline 免费插件 + Qwen2.5 大模型,零经验也能开发“对联王”微信小程序

本文详细介绍了如何利用免费的 Cline 插件辅助开发一款名为“对联王”的微信小程序,特别适合希望在春节期间创作春联的用户。文章不仅比较了 Cline 与 Cursor 两款工具的优缺点,还分享了作者实际操作中的经验和建议。通过具体步骤演示,即使是编程新手也能跟随指导,结合微信…

实现无感刷新Token技术:.Net Web API与axios的完美结合

备忘:https://mp.weixin.qq.com/s?__biz=MjM5MDE5MDM5NA==&mid=2449944319&idx=1&sn=71e84d8ee24769e77b19ca8367333b8f&chksm=b1bb10aa86cc99bc2f20686354e8184023278de74dba857a42d720dc47fabb654c12ecb83524&scene=21#wechat_redirect 我们都知道Toke…

方法引用与lambda底层原理Java方法引用、lambda能被序列化么?

系列文章目录和关于我 0.引入 最近笔者使用flink实现一些实时数据清洗(从kafka清洗数据写入到clickhouse)的功能,在编写flink作业后进行上传,发现运行的时候抛出:java.io.NotSerializableException,错误消息可能类似于 “org.apache.flink.streaming.api.functions.MapFu…