递归入门-数据结构和算法教程

news2024/11/17 15:41:46

什么是递归?

函数直接或间接调用自身的过程称为递归,相应的函数称为递归函数。使用递归算法,某些问题可以很容易地解决。这样的问题的示例是河内塔(TOH)、中序/前序/后序树遍历、图的DFS等。递归函数通过调用自身的副本并解决原始问题的较小子问题来解决特定问题。在需要时可以生成更多的递归调用。我们必须知道,我们应该提供一个特定的情况,以终止这个递归过程。所以我们可以说,每次函数调用自己时,都是用原始问题的更简单版本。

递归的性质:

  • 使用不同的输入多次执行相同的操作。
  • 在每一步中,我们尝试更小的输入,使问题更小。
  • 需要基本条件来停止递归,否则将发生无限循环。

算法:步骤

在函数中实现递归的算法步骤如下:

  • 步骤1-定义基本案例:找出已知解或解不重要的最简单的情况。这是递归的停止条件,因为它防止函数无限地调用自己。
  • 步骤2-定义递归用例:用更小的子问题来定义问题。将问题分解为更小的问题,并递归调用函数来解决每个子问题。
  • 步骤3-确保递归终止:确保递归函数最终达到基本情况,并且不会进入无限循环。
  • 步骤4-联合收割机解决方案:将子问题的解组合起来求解原问题。

数学解释

让我们考虑一个问题,程序员必须确定前n个自然数的总和,有几种方法可以做到这一点,但最简单的方法是简单地将从1到n的数字相加。这个函数看起来像这样

方法(1-简单地逐个添加

f(n) = 1 + 2 + 3 +...+ n

但是有另一种数学方法来表示它,

方法(2-递归加法

f(n) = 1             n=1
f(n) = n + f(n-1)    n>1

方法(1)和方法(2)之间有一个简单的区别,在方法(2)中,函数“f()”本身在函数内部被调用,因此这种现象被称为递归,包含递归的函数被称为递归函数,最后,这是程序员手中的一个很好的工具,可以更容易和有效地编码一些问题。

递归函数如何存储在内存中?

递归使用更多的内存,因为递归函数在每次递归调用时都会添加到堆栈中,并将值保留在那里,直到调用完成。递归函数使用LIFO(LAST IN FIRST OUT)结构,就像堆栈数据结构一样。

如何在递归中将内存分配给不同的函数调用?

当从main()调用任何函数时,内存在堆栈上分配给它。递归函数调用自身,被调用函数的内存分配在分配给调用函数的内存之上,并且为每个函数调用创建局部变量的不同副本。当达到基本情况时,函数将其值返回给调用它的函数,并且内存被释放,并且过程继续。

def printFun(test):

	if (test < 1):
		return
	else:

		print(test, end=" ")
		printFun(test-1) # statement 2
		print(test, end=" ")
		return

# Driver Code
test = 3
printFun(test)

输出:

3 2 1 1 2 3 

时间复杂度:O(1)
空间复杂度:O(1)

当从main()调用printFun(3)时,内存被分配给printFun(3),局部变量test被初始化为3,语句1到4被压入堆栈,如下图所示。它首先打印“3”。在语句2中,调用printFun(2),并将存储器分配给printFun(2),并将局部变量test初始化为2,并将语句1至4推入堆栈。类似地,printFun(2)调用printFun(1),printFun(1)调用printFun(0)。printFun(0)转到if语句,并返回printFun(1)。执行printFun(1)的其余语句,并返回printFun(2),依此类推。在输出中,打印从3到1的值,然后打印1到3。内存堆栈如下图所示。
在这里插入图片描述

现在,让我们讨论几个可以用递归解决的实际问题,并了解它的基本工作原理。如需基本了解,请阅读以下文章。

问题1:写一个程序和递归关系,找到n的斐波那契级数,其中n>2。

数学方程:
n if n == 0, n == 1;      
fib(n) = fib(n-1) + fib(n-2) otherwise;

相互关系:
T(n) = T(n-1) + T(n-2) + O(1)

递归程序:
输入:n = 5 
输出:
斐波那契数列的5个数是:0 1 1 2 3
# Function for fibonacci
def fib(n):

	# Stop condition
	if (n == 0):
		return 0

	# Stop condition
	if (n == 1 or n == 2):
		return 1

	# Recursion function
	else:
		return (fib(n - 1) + fib(n - 2))

# Driver Code

# Initialize variable n.
n = 5;
print("斐波那契数列的5个数是:",end=" ")

# for loop to print the fibonacci series.
for i in range(0,n):
	print(fib(i),end=" ")

时间复杂度:O(2^n)
空间复杂度:O(n)

这里是输入5的递归树,它清晰地展示了如何将一个大问题分解成更小的问题。
fib(n)是一个Fibonacci函数。给定程序的时间复杂度可以取决于函数调用。

fib(n) -> level CBT (UB) -> 2^n-1 nodes -> 2^n function call -> 2^n*O(1) -> T(n) = O(2^n)

最好的情况:

T(n) = θ(2^n\2)

在这里插入图片描述

问题2:编写一个程序和递归关系,找到n的阶乘,其中n>2。

数学方程:
1 if n == 0 or n == 1;      
f(n) = n*f(n-1) if n> 1;

相互关系:
T(n) = 1 for n = 0
T(n) = 1 + T(n-1) for n > 0

输入:n = 5
输出:
5的阶乘是:120

# Factorial function
def f(n):

	# Stop condition
	if (n == 0 or n == 1):
		return 1;

	# Recursive condition
	else:
		return n * f(n - 1);


# Driver code
if __name__=='__main__':

	n = 5;
	print("factorial of",n,"is:",f(n))

时间复杂度:O(n)
空间复杂度:O(n)
在这里插入图片描述

实例:递归在实际问题中的真实的应用

递归是一种强大的技术,在计算机科学和编程中有许多应用。以下是递归的一些常见应用:

  • 树和图遍历:递归经常用于遍历和搜索数据结构,如树和图。递归算法可以用于以系统的方式探索树或图的所有节点或顶点。
  • 排序算法:递归算法也用于排序算法,如快速排序和归并排序。这些算法使用递归将数据划分为更小的子数组或子列表,对它们进行排序,然后将它们合并在一起。
  • 分治算法:许多使用分治方法的算法,如二分查找算法,使用递归将问题分解为更小的子问题。
  • 分形生成:可以使用递归算法来生成分形形状和图案。例如,曼德尔布罗特集是通过将递归公式重复应用于复数而生成的。
  • 回溯算法:回溯算法用于解决涉及做出一系列决策的问题,其中每个决策都取决于先前的决策。这些算法可以使用递归来实现,以探索所有可能的路径,并在未找到解决方案时进行回溯。
  • 记忆化:记忆是一种技术,涉及存储昂贵的函数调用的结果,并在再次发生相同的输入时返回缓存的结果。记忆可以使用递归函数来实现,以计算和缓存子问题的结果。

这些只是递归在计算机科学和编程中的许多应用中的几个例子。递归是一种通用且功能强大的工具,可用于解决许多不同类型的问题。

说明:递归的一个真实的例子

递归是一种涉及函数调用自身的编程技术。它可以成为解决复杂问题的强大工具,但也需要仔细实现,以避免无限循环和堆栈溢出。

def factorial(n):
	# Base case: if n is 0 or 1, return 1
	if n == 0 or n == 1:
		return 1

	# Recursive case: if n is greater than 1, call the function with n-1 and multiply by n
	else:
		return n * factorial(n-1)

# Call the factorial function and print the result
result = factorial(5)
print(result) # Output: 120

在这个例子中,我们定义了一个名为factorial的函数,它接受整数n作为输入。该函数使用递归来计算n的阶乘(即,直到n的所有正整数的乘积)。
阶乘函数首先检查n是0还是1,这是基本情况。如果n为0或1,则函数返回1,因为0!1!都是1。
如果n大于1,则函数进入递归情况。它以n-1作为参数调用自身,并将结果乘以n。计算n!通过递归计算(n-1)!.
需要注意的是,如果不小心使用,递归可能效率低下,并导致堆栈溢出。每个函数调用都会向调用堆栈添加一个新帧,如果递归太深,则会导致堆栈变得太大。此外,递归会使代码更难理解和调试,因为它需要考虑多个级别的函数调用。
然而,递归也可以是解决复杂问题的强大工具,特别是那些涉及将问题分解为更小的子问题的问题。如果使用正确,递归可以使代码更优雅,更容易阅读。

递归VS迭代

递归:

  • 当基本情况变为true时终止。
  • 用于函数。
  • 每个递归调用都需要堆栈内存中的额外空间。
  • 更小的代码大小。

迭代:

  • 当条件变为false时终止。
  • 用于循环。
  • 每次迭代都不需要任何额外的空间。

递归编程相对于迭代编程的缺点是什么?

注意,递归和迭代程序具有相同的问题解决能力,即,每个递归程序都可以迭代地编写,反之亦然。递归程序比迭代程序具有更大的空间需求,因为所有函数将保留在堆栈中,直到达到基本情况。由于函数调用和返回的开销,它也有更大的时间需求。
此外,由于代码的长度较小,代码难以理解,因此在编写代码时必须格外小心。如果没有正确检查递归调用,计算机可能会耗尽内存。

递归编程比迭代编程有什么优势?

递归为编写代码提供了一种干净而简单的方法。有些问题本质上是递归的,如树遍历,河内塔等。对于这样的问题,最好编写递归代码。我们也可以在堆栈数据结构的帮助下迭代地编写这样的代码。例如,参考无递归的中序树遍历,迭代河内塔。

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

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

相关文章

网络安全(黑客)自学建议

建议一&#xff1a;黑客七个等级 黑客&#xff0c;对很多人来说充满诱惑力。很多人可以发现这门领域如同任何一门领域&#xff0c;越深入越敬畏&#xff0c;知识如海洋&#xff0c;黑客也存在一些等级&#xff0c;参考知道创宇 CEO ic&#xff08;世界顶级黑客团队 0x557 成员…

基于微信小程序的英语单词记忆系统的设计与实现(论文+源码)_kaic

摘 要 当前时期&#xff0c;国内的经济获得了非常快速的发展&#xff0c;互联网技术在持续的创新和完善&#xff0c;教育教学方面也在不断的进步&#xff0c;教育全面深化改革在发展&#xff0c;并且移动互联网技术在教育领域获得了大量的实践以及应用。语言的全球化慢慢的变…

【算法】01背包和完全背包

文章目录 背包问题概览01背包二维dp数组写法一维dp数组写法 完全背包关于遍历顺序相关题目[416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/)[279. 完全平方数](https://leetcode.cn/problems/perfect-squares/)[518. 零钱兑换 II](https://leet…

【webrtc】vs2017 重新构建m98

配置了一台13900k的主机,需要重新配置webrtc 构建环境代码已经gclient sync 同步好了,打算重新构建:vs2017 的win10 sdk最大17763 vs2017 环境 set vs2017_install=S:\Program Files (x86)\Microsoft Visual Studio\2017\Communitywin10 SD

Python_上下文管理器

目录 上下文管理器类 多上下文管理器 contextmanager实现上下文管理器 上下文管理器(context manager)是 Python 编程中的重要概念&#xff0c;用于规定某个对象的使用范围。一旦进入或者离开该使用范围&#xff0c;会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语…

【Kubernetes资源篇】ConfigMap配置管理中心详解

文章目录 一、ConfigMap配置中心理论知识1、ConfigMap配置中心简介2、ConfigMap局限性 二、创建ConfigMap的四种方式1、第一种&#xff1a;通过命令行创建ConfigMap2、第二种&#xff1a;通过指定文件创建ConfigMap3、第三种&#xff1a;通过指定目录创建ConfigMap4、第四种&am…

C++线程池(1)理论基础及简单实现

写过CURD的程序员肯定都熟悉“数据库连接池”这个东西&#xff0c;数据库连接是个昂贵的东西&#xff0c;因为它的创建过程比较耗费资源。所以为了节约资源、提高数据库操作的性能&#xff0c;“数据库连接池”就应运而生了。 其实线程池跟数据库连接池类似&#xff0c;一个线…

《PyTorch深度学习实践》第七讲 处理多维特征的输入

b站刘二大人《PyTorch深度学习实践》课程第七讲处理多维特征的输入笔记与代码&#xff1a;https://www.bilibili.com/video/BV1Y7411d7Ys?p7&vd_sourceb17f113d28933824d753a0915d5e3a90 Diabetes Dataset 每一行是一个记录每一列是一个特征&#xff0c;每个样本有8个特征…

为什么我们家里的IP都是192.168开头的?

为什么我们家里的IP都是192.168开头的&#xff1f; 本文为掘金社区首发签约文章&#xff0c;14天内禁止转载&#xff0c;14天后未获授权禁止转载&#xff0c;侵权必究&#xff01; 是的&#xff0c;还是我小白&#xff0c;什么技术博主&#xff0c;老情感博主了。 来讲个故事。…

网络安全合规-数据安全分类分级

数据安全是指保护数据免受未经授权的访问、使用、泄露、破坏或篡改的措施。数据安全包括物理安全、网络安全、应用程序安全、数据备份和恢复等方面。 数据分级分类是指根据数据的重要性和敏感程度&#xff0c;将数据划分为不同的级别&#xff0c;并根据不同级别的数据制定不同…

enote笔记法之附录1——“语法词”(即“关联词”)(ver0.23)

enote笔记法之附录1——“语法词”&#xff08;即“关联词”&#xff09;&#xff08;ver0.23&#xff09; 最上面的是截屏的完整版&#xff0c;分割线下面的是纯文字版本&#xff1a; 作者姓名&#xff08;本人的真实姓名&#xff09;&#xff1a;胡佳吉 居住地&#xff1…

前言-----

因要参加电赛&#xff0c;接触到STC89C52RC&#xff08;A51&#xff09;单片机 STC89C52RC引脚功能 1电源: ①VCC - 芯片电源&#xff0c;接5V&#xff1b; ②VSS - 接地端&#xff1b; 2.时钟: XTAL1、XTAL2 - 晶体振荡电路反相输入端和输出端。 3.控制线: 控制线共…

Java 17官方编程手册都针对哪些方面做了更新?

Java 17&#xff0c;官方编程手册&#xff0c; 《International Developer》杂志称为“全世界醉著名的编程书籍创作者之一”的Herbert Schildt倾情解读 《Java官方编程手册》从1996年首次出版以来&#xff0c;已经经历了数次改版&#xff0c;每次改版都反映 了Java不断演化的进…

分享解析,2+1链动模式为何能在市场上经久不衰

​小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 随…

服务网格:Istio 架构

什么是服务网格 服务网格(Service Mesh)这个术语通常用于描述构成这些应用程序的微服务网络以及应用之间的交互。随着规模和复杂性的增长&#xff0c;服务网格越来越难以理解和管理。 它的需求包括服务发现、负载均衡、故障恢复、指标收集和监控以及通常更加复杂的运维需求&am…

数据结构--双端队列

数据结构–双端队列 双端队列&#xff08;Double-ended Queue&#xff0c;简称Deque&#xff09;是一种具有队列和栈特性的数据结构&#xff0c;可以在队列的两端进行插入和删除操作。双端队列允许从前端和后端同时进行插入和删除操作&#xff0c;因此可以称为“两端都可以进出…

「STC8A8K64D4开发板」第2-6讲:串口通信

第2-6讲&#xff1a;串口通信 学习目的掌握USB转串口电路的原理和设计。学习STC8A8K64D4的串口通信&#xff0c;包括串口初始化、波特率计算、串口发送和接收。编写串口收发程序&#xff0c;尤其是串口接收的软件缓存处理。编写串口发送命令控制LED指示灯亮灭的程序。 硬件电路…

【电商API接口系列】店铺所有商品数据的采集

API接口允许不同应用程序之间共享数据&#xff0c;在系统之间传输、读取和更新数据。例如&#xff0c;一个电商网站可以通过API接口获取支付系统的支付状态。API接口允许开发人员使用他人开发的功能来扩展自己的应用程序。通过调用第三方API接口&#xff0c;开发人员无需重新实…

二进制部署Kubernetes

二进制部署Kubernetes v1.20 k8s集群master01&#xff1a;192.168.142.10 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02&#xff1a;192.168.142.20 k8s集群node01&#xff1a;192.168.142.30 kubelet kube-proxy docker k8s集群node…

基于Java汽车售票网站设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…