递归调用的理解

深入理解方法调用与递归在编程中的应用 本文深入探讨了编程中方法调用的机制,特别是递归方法的实现原理及其在解决复杂问题时的应用。通过分析DrawBranch()、drawNode()、Swap()等方法的调用,展示了方法在编程中的重要性和多样性。同时,文章还讨论了方法的定义、参数传递、返回值处理以及递归与迭代的区别。 阅读详情
关于递归调用的理解问题


前几天做题的时候,发现《数据结构高分笔记》第一章有这样一个思考题,对理解递归调用帮助很大,题目如下:



题目:逆序输出单链表的数据域,要求 指针l指向链表首元结点,且只用l一个指针


(一)分析:在单链表的情况下,要逆序输出结点数据只用一个指针,除了用递归调用,好象没有别的方法了。关键在于,如何设计递归调用?


            递归调用属于分治法的一种思想,一个包含直接或者间接调用自身函数的语句的函数被称为递归函数,但不是所有的调用自身都是递归,必须满足以下条件:
          (1)在每一次调用自身时,必须是(在某种意义上)更接近于解;
          (2)必须有一个终止 处理或者计算 的准则;


设计的算法如下:
————————————————————————————————————
void reversePrint(LNode *l)                                            //逆序输出链表
{
if (l->next!= NULL){
reversePrint(l->next);
}
cout << l->data<<" -- ";
}
————————————————————————————————————
            我们假设从首元结点到尾元结点共有9个结点,指针l指向首元结点,当执行到if语句时,很明显” l->next!= NULL “成立,于是执行“ reversePrint(l->next); ”进入递归第二层,第二层循环执行到if语句后同样” l->next!= NULL “成立,于是进入到递归第三层……值得说明的是“ reversePrint(l->next); ”语句中,( )中必须写成”( l->next )“,如果写成(l),便会进入死循环,违背了上面条件(1)。而” l->next!= NULL “就是终止处理的准则,也就是上面的条件(2);
            
            当进入递归第九层以后,” l->next!= NULL “不成立,于是直接执行" cout << l->data<<" -- "; "输出结点9的数据,第九层递归执行结束。但第九层递归执行结束以后,第八层递归if语句执行完毕,也进入" cout << l->data<<" -- "; "语句输出结点9的数据域,第八层递归执行结束。以此类推,7、6、5、4、3、2、1依次执行" cout << l->data<<" -- "; "语句,于是整个链表就被逆序输出,而且从头到尾l指针所指的始终是首元结点(每一层的l可以看成每一层自己定义的指针,只不过名字相同,这点很重要)。因此,使用指针l,如果用for循环输出则为正序,使用递归就可以达到逆序输出的目的。


        另外值得一提的是" cout << l->data<<" -- "; "语句的位置因该放在函数哪里,也是一个值得深思的问题。 


(二)关于递归调用的时间复杂度问题
        如上九个结点,九层循环的时间复杂度为9,也就是说这个算法时间复杂度为O(n)。初学者可能会怀疑时间复杂度为n次方,但是仔细比较就会发现,递归和循环的时间复杂度很类似。递归九层逆序输出,时间复杂度为9;for(i=1;i<=9;i++){……}循环顺序输出9次,时间复杂度也是9。


        因此,灵活的使用递归和循环,可以解决线性表的各种顺序以及逆序问题!




完整的代码如下(VS2013编译环境):
————————————————————————————————————
//  逆序打印单链表的数据    指针l指向链表开始  要求只用l一个指针
/*
分析: 采用递归   printNode {if(l->next!=NULL)printNode(l->next);cout<<l->data;}


         很神奇的想法!对理解递归有很大帮助!!!
*/
#include "stdafx.h"
#include <iostream>
#include "stdlib.h"
using namespace std;
static int length = 9;


typedef struct LNode{                                                            //结点的定义
int data;
struct LNode *next;
}LNode;


LNode *createLink( )//创立链表 
{
//创立头结点
LNode *head;
head = (LNode *)malloc(sizeof(LNode));
head->data = 0; head->next = NULL;
//创立剩下的结点
LNode *newNode, *p = head;
for (int i = 1; i <= length; i++) {
newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = i; newNode->next = NULL;
p->next = newNode;
p = p->next;
}
return head;
}


void printLink(LNode *head)//输出链表 
{
cout << "当前链表为:";
LNode *temp = head->next;
do{
cout << temp->data << " -- ";
temp = temp->next;
} while (temp->next!=NULL);
cout << temp->data;
cout << endl;
}


void reversePrint(LNode *l)                                            //逆序输出链表
{
if (l->next!= NULL){
reversePrint(l->next);
}
cout << l->data<<" -- ";
}


int _tmain(int argc, _TCHAR* argv[])
{
LNode *head = createLink();
printLink(head);
cout << "逆序链表为:";
reversePrint(head->next);
        cout << endl;
return 0;
}
————————————————————————————————————


输出结果如下: 



使用 Python+PaddleOCR 实现图文识别:从入门到精通 在当今数字化时代,图文识别技术的应用越来越广泛,如文档数字化、信息提取等。PaddleOCR 是百度开源的一款强大的 OCR 工具包,它集成了多种先进的算法和模型,能够高效准确地进行图文识别。本文将详细介绍如何使用 PaddleOCR 和 Python 实现图文识别,并给出具体的代码和步骤。 阅读详情

相关推荐

MATLAB实战:手把手教你用三频四步相移法搞定结构光三维重建(附完整代码)

本文详细介绍了如何使用MATLAB实现三频四步相移法进行高精度结构光三维重建。通过光栅图像预处理、相位计算、多频外差与相位解包裹等步骤,结合完整代码示例,帮助读者掌握从二维图像到三维点云的关键技术。该方法在工业检测和逆向工程中具有抗干扰能力强、高分辨率和鲁棒性等优势。

weixin_29201933的博客 339

方法递归调用(非常非常重要,比较难)

今天,我们来学习一下方法的递归,希望我的讲解可以让您对方法的递归调用有更深的了解。递归调用就是在当前的函数中调用当前的函数并传给相应的参数,这是一个动作,这一动作是层层进行的,直到满足一般情况的的时候,才停止递归调用,开始从最后一个递归调用返回。简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变 得简洁。2、各种算法中也会使用到递归,比如快排,归并排序,二分查找,分治算法等。3、将用栈解决的问题,代码实现变得更加简洁。.........

qq_64513441的博客 3566

STM32+4G模块+MQTT协议:从零构建稳定可靠的物联网通讯链路

本文详细介绍了如何利用STM32、4G模块和MQTT协议构建稳定可靠的物联网通讯链路。通过硬件选型、AT指令配置和MQTT连接实战,帮助开发者实现低功耗、高可靠性的数据传输,特别适合户外和移动场景应用。

weixin_29191081的博客 334

函数的使用之递归调用

在前面的几篇文章中,我们了解并使用了一些函数的基本用法,但函数除了能够被主函数调用以外,其实还能被自己或是其他的函数调用,而这种特殊的用法就是我们今天讲到的——函数的递归调用。

Lin050421的博客 4934

汽车零部件智能装配:C#+YOLOv8实现螺栓漏装检测与齿轮错位识别(附PLC通信与机械臂控制)

YOLOv8:小目标检测的最优解相比YOLOv7,YOLOv8的C2f特征融合网络对小目标(5-10mm螺栓)检测精度提升12%,且推理速度快8%;支持大输入尺寸(不显著增加耗时),可放大螺栓细节;官方提供yolov8n.pt(nano版),在边缘计算盒上能跑40+FPS,满足实时性。C#:工业软件的“兼容性核心”主流PLC(西门子S7-1200/1500)、机械臂(ABB、KUKA)的SDK多基于.NET开发,C#可直接调用,避免跨语言通信延迟;多线程管理成熟(Task。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1146

深入解析高通8155平台音频数据流:从HAL到DSP的完整链路

本文深入解析了高通8155平台音频数据从安卓HAL层到DSP的完整传输链路。以播放场景为例,详细阐述了音频数据如何通过ASoC DPCM框架进行路由、打包,并经由APR协议与DSP交互,最终驱动硬件发声的核心流程,为车载音频系统开发与调试提供了清晰的框架。

rust6ferris的博客 1176

C++实现链表

C++实现链表。本文介绍两种实现方法:一、使用指针自定义实现;二、使用C++ STL(标准模板库)中的list容器实现。

cnds123的专栏 6182

AutoSAR配置视频讲解:新建DaVinci工程

AutoSAR实验视频讲解:闪烁一颗LED实验【新建DaVinci工程】 上一篇 | 下一篇 | 总目录 实验架构图 视频本频放在了文末,下图描述了本次实验配置内容在AutoSAR架构中的位置,供大家参考 实验内容 本节课程讲解新建DaVinci工程,听上去新建工程很简单,但是还是需要很多的准备工作和细节。主要内容是新建工程和导入dbc文件和导入arxml文件的方法 主要步骤 新建DaVinci工程 导入.dbc通信矩阵文件 导入Mcal的arxml文件 实验视频2:Mcal配置 提示:版权所在,违

雪云飞星的博客 6276

javascript递归函数定义和常见递归算法

javascript递归函数定义和常见递归算法

zyf971020的博客 1017

半车(前后、左右)、整车悬架详细推导建模和simulink仿真分析

用达朗贝尔定理依据悬架数学模型,得到悬架模型微分方程,分别用simulink建立前后半车、左右半车悬架;结合转向2自由度模型与半车侧倾模型,对模型考虑相干性、延时性的C级随机路面下,仿真分析给定角阶跃输入下的侧倾稳定性。

Mr.邹的博客 1万+

西门子PLC编程之⑦编程开始之点位配置及注释

紧接上篇,点位梳理后,进入PLC编程。1、新建工程,配置系统模块2、配置I点并做中文符合,直接上中文,smart支持中文点位编程,用起来很方便。3、配置Q点并做中文符合5、配置AIW模拟量输入点,配置AQW模拟量输出点并做中文符合6、配置手动启动辅助触点,并做中文符合7、 配置自动启动辅助触点,并做中文符合8、 配置传感器浮点型数据变量点位,并做中文符合9、配置系统运行参数设置区点位,做中午符合,做掉电保持.....................

学技术,人生不误——谁也是寂寞宇宙里的流星,只是你的坚持决定了你划过的痕迹。而且,铸造了普遍里的你的唯一。 4890

循环队列(顺序结构)

循环队列(顺序结构)

q322359的博客 764

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【C++】递归(1)--包含一个递归调用的递归理解

递归是一层一层进去,然后再从最里面一层一层出来;比如你买了一个俄罗斯套娃,一共3层,大白+中黑+小红: 大-->>中-->>小这样进来,然后红-->>黑-->>白 出来!

王博(Kings)的博客 2155

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

自己理解的递归-调用的方法

刷题加看文章终于对递归有了一点认识,为了防止遗忘记录一下。 首先按我的理解递归就是栈+函数调用 比如下面的调用 func_A() { func_B(); } func_B() { func_C(); } func_C() { / } 调用函数A; 调用函数B; 调用函数C; 函数C返回; 函数B返回; 函数A返回; 来一个前序遍历的例子 按图中的例子,1会按顺序调用2和3、2按顺序调用4和5,3按顺序调用6和7…所以8这个点肯定比所有右子树先调用。但8之后没有调用的数了,也就是return这一步,这一步可

weixin_45117094的博客 142

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

通过栈的方式理解递归调用

本章主要介绍了程序在cpu和内存的工作过程,以及通过栈的方式来理解递归的过程。内存中以栈的形式来存储指令和数据,其中对于数组和对象在栈中以地址的形式,而不是具体数据,具体数据存放在堆中。

m0_52933200的博客 353

对For循环里的递归调用的理解

菜鸟学编程 1263

笔记_递归调用的理解

学习方法这部分内容的时候,对返回值很难理解,什么是返回值,返回值是干嘛用的,返回值最后返回到哪里去,如果没有返回值,方法会怎么样,这些都是萦绕在心头的问题。后来看到关于递归调用这部分内容的时候,对于返回值有了一丝丝开窍,赶紧把灵感记下来,这仅仅是我个人的理解。         递归调用,其实就是调用函数本身,这么说可能还会是一头雾水,但我在网上看到有人做了一个很形象的解释:说从前有座山,山里有座

布布熊的博客 403

对递归调用的理解

没每一块 每个方法 也就是每一块在栈中都会有一个空间,空间中的n 是独立的。 每次的调用自身,也就相当于暂停,等方法中真正有效的代码执行之后,继续 其实方法中的判断条件就像是while中的判断条件一样。只不过参数是逆序的 递归最好的理解方式就是拼接,想想String。 package a; public class Self { public static void main(Strin...

Be_With_I的博客 277

深入理解递归函数的调用过程

原文见链接深入理解递归函数的调用过程

黎明前的沉睡 529

递归调用理解【含有示例代码】

1 每一级的函数调用都有自己的局部变量.2 递归函数中,位于递归调用语句后的语句的执行顺序和各个被调用函数的顺序相反.    即位于递归函数入口前的语句,由外往里执行;    位于递归函数入口后面的语句,由里往外执行。 3 虽然每一级递归有自己的变量,但是函数代码并不会得到复制.4 递归函数中必须包含可以终止递归调用的语句.“` int region(int a[], int cur

xbog的思考记录 515

21-函数的递归调用的理解

案例: <?php //函数的递归调用 function abc($n){ if($n>2){ abc(--$n); } echo '$n='.$n.""; } abc(4); ?> 案例2: <?php //函数的递归调用 function abc($n){ if($n>2){ abc(--$n); }e

高调做事,低调做人! 1103

从"把大象放冰箱"理解递归调用

递归算法中递是"去"的意思, 归是"回"的意思, 整个递归就是"有去有回"的过程. 什么样的问题要用递归来解决?一句话: 对于问题N,如果N-1已经解决了,那么N是否很容易解决。 学递归调用要明确以下三点: 1、整个递归的终止条件是什么? 2、应该返回给上一级的的返回值是什么? 3、一级递归要做什么?(重复逻辑) 其实2可以和3合并: 1.递归终止条件 2.把问题规模缩小 ...

一江明澈的水的专栏 823
上一篇: C&amp;C++关于数组的定义,引用传参问题
下一篇: 循环体变量利用的小技巧
K_zer0
博客等级 码龄11年 7粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值