3.4 栈与递归

news2024/10/6 18:20:54

3.4.1 采用递归算法解决问题 

3.4 栈与递归的关系

栈和递归之间有着紧密的关系,特别是在算法和程序设计中。栈作为一种数据结构,可以有效地支持递归算法的实现。本节我们将详细讨论栈在递归算法中的作用及其在程序设计中的重要性。

1. 递归算法的基本概念

  • 定义和特点
    • 递归是一种算法结构或编程技巧,其中函数直接或间接地调用自身来解决更小的问题实例。
    • 递归算法通常包含基本情况(终止条件)和递归步骤(自我调用来解决更小的问题)。

2. 栈在递归中的角色

  • 概述

    • 在实现递归时,栈被用作一个辅助数据结构,用于保存函数调用的信息,如返回地址和局部变量。
    • 栈的后进先出(LIFO)特性确保了函数调用的正确执行和返回。
  • 详细描述

    • 保存返回地址:在函数调用时,返回地址被推送到栈中,以便函数可以在执行完毕后返回到正确的位置。
    • 存储局部变量:函数的局部变量也存储在栈中,保证了在每次函数调用时,变量的正确初始化和使用。

3. 递归算法的设计和实现

  • 基本步骤

    • 确定基本情况:定义递归算法的终止条件。
    • 递归表达式:描述如何通过解决更小的问题来解决当前问题。
  • 示例代码

    #include <stdio.h>
    
    int factorial(int n) {
        if (n == 0) {
            return 1; // 基本情况,0的阶乘为1
        } else {
            return n * factorial(n - 1); // 递归表达式,n的阶乘是n乘以n-1的阶乘
        }
    }
    
    int main() {
        int number = 5;
        printf("The factorial of %d is %d\n", number, factorial(number));
        return 0;
    }
    

4. 栈和递归在程序设计中的应用

  • 实例分析
    • 在计算机科学中,栈和递归常用于解决各种问题,如数据结构操作(如树的遍历)、图形算法(如分治算法)和动态编程等。
    • 通过理解栈和递归的关系,程序员可以更好地设计和实现高效的算法。

注意事项

  • 递归算法需要仔细设计基本情况和递归步骤,以避免无限递归和堆栈溢出错误。
  • 递归虽然可以使代码更简洁和优雅,但也可能导致效率降低和内存使用增加,因此应谨慎使用。

 

 

3.4.2 递归的过程与递归工作栈 

3.4.2 递归过程与递归工作栈

在这段文本中,对递归过程和递归工作栈的概念和运行机制进行了详细阐述。现在我将帮你逐点分析这些内容:

递归函数的运行机制

  1. 函数调用机制: 在程序中,函数可以调用其他函数,而递归则是函数调用自身。在函数调用中,调用函数和被调用函数的信息交换和链接是通过栈来实现的。

  2. 函数调用和返回的过程

    • 调用前需完成:
      1. 传递实参和返回地址给被调用函数。
      2. 为被调用函数的局部变量分配存储区。
      3. 控制转移到被调用函数。
    • 返回前需完成:
      1. 保存被调用函数的计算结果。
      2. 释放被调用函数的数据区。
      3. 根据保存的返回地址将控制转移到调用函数。
  3. 递归函数的层次概念: 在递归函数中,每次调用都会形成一个新的层次。这些层次和调用的顺序密切相关,可以通过递归工作栈来保持跟踪。

递归工作栈

  1. 递归工作栈的定义: 递归工作栈用于在递归过程中存储每一层递归所需的信息(如实参、局部变量和返回地址)。每次进入一个新的递归层次时,都会生成一个新的工作记录(或称活动记录)并压入栈顶。每次退出一个递归层次时,则从栈顶弹出一个工作记录。

  2. 递归函数的运行示例: 以下是一个简化的阶乘函数递归调用过程的示例代码,解释了在递归过程中栈的运行情况和活动记录的使用:

    #include <stdio.h>
    
    long Fact(long n) {
        long temp;
        if (n <= 0) return 1;
        else {
            temp = n * Fact(n - 1);
            return temp;
        }
    }
    
    int main() {
        long n = 4;
        long result = Fact(n);
        printf("The factorial of %ld is: %ld\n", n, result);
        return 0;
    }
    

    解析

    • main 函数调用 Fact(4),进入第一层递归。
    • Fact(4) 调用 Fact(3),进入第二层递归,这一过程继续,直到调用 Fact(0),此时达到递归基条件,返回1。
    • 接着开始从栈顶逐步弹出每层递归的工作记录,计算并返回结果到上一层,直到最终返回到 main 函数。

结论

通过这段文本,我们可以更好地理解递归函数的运行机制和递归工作栈的工作原理。

 

 3.4.3 递归算法的效率分析

这段文本对递归算法的效率进行了深入的分析,涉及时间复杂度和空间复杂度的计算。下面我会针对这些内容提供详细的解析:

### 3.4.3 递归算法的效率分析

#### 1. 时间复杂度的分析

在递归算法的分析中,时间复杂度通常通过建立递归方程来计算。递归方程的求解可以通过多种方法,其中一种是迭代法。迭代法通过将递归方程不断展开,最终将其转换为一个非递归的和式,然后估算这个和式来得到方程的解。

例如,我们可以使用迭代法来分析阶乘函数`Fact(n)`的时间复杂度:

int Fact(int n) {
      if (n == 0) 
          return 1;
      else 
          return n * Fact(n - 1);
  }

- **递归方程建立:**
  递归函数`Fact(n)`的执行时间可表示为`T(n)`,其中

  其中D和C是常数,代表各个操作的执行时间。

- **递归方程解析:**
  通过迭代法我们可以将`T(n)`不断展开,直至找到一个模式或达到一个已知条件。按照文本的描述,我们可以得到`T(n) = nC + D`,因此时间复杂度为O(n)。

#### 2. 空间复杂度的分析

在递归算法中,系统使用“递归工作栈”来存储每层递归所需的信息,这是分析递归算法空间复杂度的关键。

- **递归工作栈的概念:**
  递归工作栈是用于存储每次递归调用所需的信息(如参数、局部变量和返回地址等)的数据结构。

- **空间复杂度计算:**
  对于递归算法,空间复杂度通常可以表示为

,其中是递归工作栈中工作记录数量与问题规模n的函数关系。例如,在阶乘问题、斐波那契数列问题和汉诺塔问题中,空间复杂度都是O(n),因为工作栈中的记录数量与n成正比。

 

3.4.4 利用栈将递归转换为非递归的方法 

3.4.4 利用栈将递归转换为非递归的方法

在解析递归算法时,我们可以注意到它依赖于系统提供的隐式栈来执行。根据递归算法执行过程中的递归工作栈的状态变化,我们可以编写相应的非递归算法。以下是消除递归过程的具体步骤:

(1) 创建工作栈

创建一个工作栈来存储递归工作记录,包括实参(实际参数)、返回地址和局部变量等。

(2) 初始化非递归调用

在非递归调用的入口(被调用程序的开始处),初始化实参和返回地址。由于递归程序不能作为主程序,我们可以假设它最初是由某个调用程序调用的。

(3) 模拟递归分解过程

当不满足递归结束条件时,逐层递归,将实参、返回地址和局部变量压入栈中。这个过程可以通过循环语句来实现,从而模拟递归分解的过程。

(4) 设置递归退出条件

当递归结束条件被满足时,将给定常数作为当前函数值,标记递归的结束。

(5) 模拟递归求值过程

在栈不为空的情况下,重复执行以下步骤:弹出栈顶记录,根据记录中的返回地址执行特定的操作,即逐层计算当前函数值,直到栈为空为止。

结论

通过以上步骤,我们可以将任何递归算法转换为非递归算法。但是,这样改写后的非递归算法通常会失去原有的结构清晰度和可读性,有时还需进一步优化。更多具体实例可以参见本文后续的5和5.1节,其中包含二叉树中序遍历的非递归算法示例。

 

 

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

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

相关文章

C#和.NET FrameWork概述

.NET FrameWork是什么&#xff1f; .NET FrameWork是由微软开发的一种面相对象的环境框架&#xff0c;特点如下&#xff1a; ①多平台&#xff1a;可在各种计算机、服务器、手机上运行。 ②标准化通讯协议&#xff1a;如XML、HTTP、JSON等。 ③安全性&#xff1a;CLR检查并…

通过实例学习鸿蒙静态库的创建与使用

简要介绍 静态共享包HAR&#xff08;Harmony Archive&#xff09;&#xff0c;是为了实现代码和资源的共享&#xff0c;可以包含代码、C库、资源和配置文件&#xff0c;随使用方一起编译&#xff0c;如果在多个应用中进行调用&#xff0c;就需要有多个HAR&#xff0c;和应用绑…

修改Tomcat的默认端口号

1、找到Tomcat的安装路径。 2、打开conf文件夹。 3、用记事本打开server.xml文件 4、找到 <Connector port"8080" protocol"HTTP/1.1"&#xff0c;其中的8080就是tomcat的默认端口&#xff0c;将其修改为你需要的端口即可。

图书管理信息系统分析与设计

一、系统开发的可行性分析 &#xff08;一&#xff09;系统背景.必要性及意义 随着社会经济的迅速发展和科学技术的全面进步&#xff0c;计算机事业的飞速发展&#xff0c;以计算机与通信技术为基础的信息系统正处于蓬勃发展的时期。随着经济文化水平的显著提高&#xff0c;人…

数据接口工程对接BI可视化大屏(六)接收前台数据

文章目录 第6章 接收前台数据6.1 模拟数据6.2 接收数据6.2.1 编写Dao6.2.2 编写ServiceImpl6.2.3 编写Controller6.2.4 验证 后记 第6章 接收前台数据 在工作中也会遇到需要接收前台发送数据&#xff0c;进行存储的情况。这里以接收日志服务器的日志数据保存到kafka为例。 6.…

久运恒远聚焦物业多营渠道致力服务美好生活

随着社会的不断发展和人民生活水平的不断提高&#xff0c;物业行业已经逐渐向深度服务化方向调整&#xff0c;物业的多种经营体系也成为品牌关注和布局的重要销售渠道。久运恒远&#xff08;北京&#xff09;企业管理有限公司聚焦物业多营体系&#xff0c;整合资源&#xff0c;…

CTFHub | 综合过滤练习

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

简单5步骤搞定windows server2019 配置IIS支持PHP

测试成功&#xff0c;记录一笔&#xff0c;感谢网上各位大佬的技术支持。 一、安装vcredist_x64.exe 否则可能会出现 FastCGI进程意外退出 二、IIS开启CGI&#xff08;可能需要重启&#xff09; 控制面板&#xff0c;启用或关闭windows程序&#xff0c;IIS--应用程序开发--CGI…

61、SpringBoot -----跨域资源的设置----局部设置和全局设置

★ 跨域资源共享的意义 ▲ 在前后端分离的开发架构中&#xff0c;前端应用和后端应用往往是彻底隔离的&#xff0c;二者不在同一个应用服务器内、甚至不再同一台物理节点上。 因此前端应用和后端应用就不在同一个域里。▲ 在这种架构下&#xff0c;前端应用可能采用前端框架&a…

Linux入门教程||Linux系统目录结构

登录系统后&#xff0c;在当前命令窗口下输入命令&#xff1a; ls / 你会看到如下图所示: 树状目录结构&#xff1a; 以下是对这些目录的解释&#xff1a; /bin&#xff1a; bin是Binary的缩写, 这个目录存放着最经常使用的命令。 /boot&#xff1a; 这里存放的是启动Linux时…

【AIGC专题】Stable Diffusion 从入门到企业级实战0601

一、前言 本章是《Stable Diffusion 从入门到企业级实战》系列的第六部分Prompt专题篇《Stable Diffusion Prompt 专题》第01节 《Stable Diffusion Prompt 通用画风操作实战》。本部分内容&#xff0c;位于整个Stable Diffusion生态体系的位置如下图黄色部分所示&#xff1a;…

RJ45水晶头网线顺序出错排查

线序 网线水晶头RJ45常用的线序标准ANSI / TIA-568定义了T568A与T568B两种线序&#xff0c;一般使用T568B&#xff0c;水晶头8个孔对应的8条线颜色如下图&#xff1a; 那1至8的编号&#xff0c;是从水晶头哪一面为参考呢&#xff0c;如下图&#xff0c;是水晶头金手指一面&am…

SAP ABAP基础知识 访问外部数据库-开发篇

前言 本文主要介绍通过ABAP语言访问外部数据库的几种方式 一、外部数据库配置 本文示例中的代码访问了两个外部数据库 MTD : 外部oracle数据库,其中示例表 ZTTEMP 字段( ZZTNO,WERKS) S4Q : 外部HANA数据库(开发系统访问测试系统的数据库), 使用表USR02,ZTTEMP 二、ABAP访问…

YOLO物体检测系列2:YOLOV2整体解读

1、YOLOV1 优点&#xff1a;快速&#xff0c;简单&#xff01;问题1&#xff1a;每个Cell只预测一个类别&#xff0c;如果重叠无法解决问题2&#xff1a;小物体检测效果一般&#xff0c;长宽比可选的但单一 YOLOV2更快&#xff01;更强&#xff01; 2、Batch Normalization …

群晖NAS教程(二十五)、利用web station安装nextcloud

群晖NAS教程(二十五)、利用web station安装nextcloud 一、下载离线安装包文件 下载地址https://download.nextcloud.com/server/releases/&#xff0c;我们选择zip格式的&#xff0c;下载这个latest-27.zip的最新版的。 把它加压缩到群辉web/hepnextcloud路径下&#xff0c;并…

算法:贪心---跳一跳

1、题目&#xff1a; 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 2…

包管理工具--》其他包管理器之cnpm、pnpm、nvm

包管理工具系列文章目录 一、包管理工具--》npm的配置及使用&#xff08;一&#xff09; 二、包管理工具--》npm的配置及使用&#xff08;二&#xff09; 三、包管理工具--》发布一个自己的npm包 四、包管理工具--》yarn的配置及使用 五、包管理工具--》其他包管理器之cnpm…

Codeforces Round 790 (Div. 4) D 求矩形里面斜线的和的最大值

Codeforces Round 790 (Div. 4) D 做题链接&#xff1a;https://codeforces.com/contest/1676/problem/D 帖木儿的爷爷送给他一个棋盘&#xff0c;让他练习棋艺。这个棋盘是一个a行n列的网格&#xff0c;每个单元格都写有一个非负整数。 帖木儿的挑战是在棋盘上放置一只主教&…

Sweet Home 3D for Mac(3D室内装潢设计软件)

如果你想设计一个美丽而舒适的家居空间&#xff0c;那么Sweet Home 3D for Mac(3D室内装潢设计软件)是一个不可或缺的工具。 Sweet Home 3D for Mac是一款功能强大的室内装潢设计软件&#xff0c;专为Mac用户设计。 它提供了一个直观而易于使用的界面&#xff0c;使您能够轻松…

【Y 码力】WAL 与性能

【Y 码力】: 是由 YMatrix 研发团队负责的栏目&#xff0c;栏目专注介绍数据库的底层原理、实现细节&#xff0c;以及YMatrix 研发团队不断探索中的工程实践。我们希望栏目能够成为数据库技术的显微镜&#xff0c;同时也能够成为大家了解 YMatrix 研发团队的一扇窗。 摘要 谈…