【算法】递归与尾递归总结

十进制转换为二进制字符串 #include <iostream> #include <algorithm> #include <cstring> #include <fstream> using namespace std; string toNumber(int n){ string s; if(n==0) return "0"; else{ while(n)... 阅读详情

前言:今天上网看帖子的时候,看到关于尾递归的应用(http://bbs.youkuaiyun.com/topics/390215312),大脑中感觉这个词好像在哪里见过,但是又想不起来具体是怎么回事。如是乎,在网上搜了一下,顿时豁然开朗,知道尾递归是怎么回事了。下面就递归与尾递归进行总结,以方便日后在工作中使用。

1、递归

  关于递归的概念,我们都不陌生。简单的来说递归就是一个函数直接或间接地调用自身,是为直接或间接递归。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。用递归需要注意以下两点:(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。

递归一般用于解决三类问题:
   (1)数据的定义是按递归定义的。(Fibonacci函数,n的阶乘)
   (2)问题解法按递归实现。(回溯)
   (3)数据的结构形式是按递归定义的。(二叉树的遍历,图的搜索)
递归的缺点:
  递归解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成栈溢出。
  用线性递归实现Fibonacci函数,程序如下所示:
1 int FibonacciRecursive(int n)
2 {
3     if( n < 2)
4         return n;
5     return (FibonacciRecursive(n-1)+FibonacciRecursive(n-2));
6 }

递归写的代码非常容易懂,完全是根据函数的条件进行选择计算机步骤。例如现在要计算n=5时的值,递归调用过程如下图所示:

2、尾递归

  顾名思义,尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量. 直接让被调用的函数返回时越过调用者, 返回到调用者的调用者去。尾递归就是把当前的运算结果(或路径)放在参数里传给下层函数,深层函数所面对的不是越来越简单的问题,而是越来越复杂的问题,因为参数里带有前面若干步的运算路径。

  尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。比如f(n, sum) = f(n-1) + value(n) + sum; 会保存n个函数调用堆栈,而使用尾递归f(n, sum) = f(n-1, sum+value(n)); 这样则只保留后一个函数堆栈即可,之前的可优化删去。

  采用尾递归实现Fibonacci函数,程序如下所示:

1 int FibonacciTailRecursive(int n,int ret1,int ret2)
2 {
3    if(n==0)
4       return ret1; 
5     return FibonacciTailRecursive(n-1,ret2,ret1+ret2);
6 }

例如现在要计算n=5时的值,尾递归调用过程如下图所示:

从图可以看出,为递归不需要向上返回了,但是需要引入而外的两个空间来保持当前的结果。

  为了更好的理解尾递归的应用,写个程序进行练习。采用直接递归和尾递归的方法求解单链表的长度,C语言实现程序如下所示:

复制代码
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct node
 5 {
 6   int data;
 7   struct node* next;
 8 }node,*linklist;
 9 
10 void InitLinklist(linklist* head)
11 {
12      if(*head != NULL)
13         free(*head);
14      *head = (node*)malloc(sizeof(node));
15      (*head)->next = NULL;
16 }
17 
18 void InsertNode(linklist* head,int d)
19 {
20      node* newNode = (node*)malloc(sizeof(node));
21      newNode->data = d;
22      newNode->next = (*head)->next;
23      (*head)->next = newNode;
24 }
25 
26 //直接递归求链表的长度 
27 int GetLengthRecursive(linklist head)
28 {
29     if(head->next == NULL)
30        return 0;
31     return (GetLengthRecursive(head->next) + 1);
32 }
33 //采用尾递归求链表的长度,借助变量acc保存当前链表的长度,不断的累加 
34 int GetLengthTailRecursive(linklist head,int *acc)
35 {
36     if(head->next == NULL)
37       return *acc;
38     *acc = *acc+1;
39     return GetLengthTailRecursive(head->next,acc);
40 }
41 
42 void PrintLinklist(linklist head)
43 {
44      node* pnode = head->next;
45      while(pnode)
46      {
47         printf("%d->",pnode->data);
48         pnode = pnode->next;
49      }
50      printf("->NULL\n");
51 }
52 
53 int main()
54 {
55     linklist head = NULL;
56     int len = 0;
57     InitLinklist(&head);
58     InsertNode(&head,10);
59     InsertNode(&head,21);
60     InsertNode(&head,14);
61     InsertNode(&head,19);
62     InsertNode(&head,132);
63     InsertNode(&head,192);
64     PrintLinklist(head);
65     printf("The length of linklist is: %d\n",GetLengthRecursive(head));
66     GetLengthTailRecursive(head,&len);
67     printf("The length of linklist is: %d\n",len);
68     system("pause");
69 }
复制代码

程序测试结果如下图所示:

参考:http://www.cnblogs.com/JeffreyZhao/archive/2009/03/26/tail-recursion-and-continuation.html


转载链接:http://www.cnblogs.com/Anker/archive/2013/03/04/2943498.html

Python数据类型转换 Python数据类型转换 type()查看数据类型 函数 说明 int(x[,base]) 将x转换为整数,[,base]表示x的进制 float(x) 将x转换为浮点数 str(x) 将x转换为字符串 bool(x) 将x转换为布尔值 转换为整数 int(x) print(int("123"))#结果:123,将字符串"123"转换为整数123 print(int(12.34))#结果:12,将浮点数12.34转换为整数12 print(int(True)) #结果 阅读详情

相关推荐

算法精解-C语言描述 递归和尾递归 (图解+实例)

递归是一种强大的方法,它允许一个对象以其自身更小的形式来定义自己。 让我们来观察一下自然界中出现的递归现象:蕨类植物的叶子,每片叶子叶脉中的小分支都是整片叶子的较小缩影;又或者两个反光的物体,相互映射对方渐远的影像。这样的例子使我们明白,尽管大自然的力量是强大的,在许多方面它那种出乎意料的简洁更让我们觉得优美。同样的道理也可以用在递归算法上,从很多方面来说递归算法都是简洁而优美的,而且非常强大。

idreamo的博客 6142

尾递归(Tail Recursion)

向上递归(Pass-Up Recursion) 先来看一下传统的递归 def sum(lst): """把lst所有元素求和""" if len(lst) = 0: return 0 return lst[0] + sum(lst[1:]) 加入sum([1,2,3]),则是先求sum([2,3]);而要求sum([2,3]),则要求sum([3]), 求sum([3])则要求sum([]), sum([])=0;依次返回。 sum([3])=3 + 0 = 3 sum([2, 3]) = 2

Ennis_Tongji的博客 970

Material Statuses,在 SAP 物料主数据里控制物料能不能用,不只是一个状态字段

SAP物料主数据中的Material Statuses常被低估,实则影响多个业务模块。它通过跨工厂、工厂特定、跨分销链和分销链特定四类状态控制物料生命周期,各状态会联合作用。正确配置状态可精准控制研发、采购、生产、销售等环节的物料使用权限,避免单纯依赖删除标记或权限带来的业务风险。实施时需注意状态编码无固定语义,应结合企业实际业务流程配置,并通过标准接口更新数据。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1229

递归与尾递归总结

  前言:今天上网看帖子的时候,看到关于尾递归的应用(http://bbs.youkuaiyun.com/topics/390215312),大脑中感觉这个词好像在哪里见过,但是又想不起来具体是怎么回事。如是乎,在网上搜了一下,顿时豁然开朗,知道尾递归是怎么回事了。下面就递归与尾递归进行总结,以方便日后在工作中使用。 1、递归   关于递归的概念,我们都不陌生。简单的来说递归就是一个函数直接或间接地调用自...

weixin_33841722的博客 599

递归与尾递归在算法中的应用与优化

本文深入探讨了递归与尾递归的概念,通过“皮划艇问题”的案例分析了递归在解决动态规划问题中的应用,以及如何通过尾递归优化递归函数的性能。文章还介绍了使用累加器将非尾递归函数转换为尾递归函数的方法,并通过实例展示了如何应用这些技术。通过具体的编程练习,读者可以更深刻地理解尾递归的原理及其在实际编程中的重要性。

weixin_36299472的博客 506

鸿蒙OS+UniApp文件上传实战:如何解决大文件分片上传的3大坑?

本文深入探讨鸿蒙OS与UniApp结合实现大文件分片上传的实战方案,重点解决分片策略设计、网络中断处理和进度管理三大技术难题。通过鸿蒙分布式特性与UniApp跨平台能力的结合,提供动态分片调整、断点续传和跨设备进度同步等优化方案,显著提升大文件上传成功率和用户体验。

weixin_29250403的博客 475

尾递归算法

尾递归算法最佳实践

coder_kuroneko 1151

MR2数据集实战:5步搞定多模态谣言检测模型训练(附完整代码)

本文详细介绍了如何使用MR2多模态数据集构建高精度谣言检测系统,涵盖环境配置、数据准备、多模态特征工程、模型架构设计、训练调优及部署优化等5个关键步骤。通过双线性融合技术处理文本、图像和网页三模态数据,解决特征对齐和模态冲突等工程难题,并提供完整代码实现和性能优化方案。

weixin_42657024的博客 241

递归算法和尾递归

递归算法和尾递归

Charge8的博客 1709

【无人机对抗】基于matlab无人机红蓝对抗仿真【含Matlab源码 4436期】

无人机红蓝对抗仿真 完整代码,包运行;可提供运行操作视频!适合小白!

Matlab3024528700的博客 1380

UE5实战技巧:TextRender高效集成中文字体与材质优化

本文针对UE5中TextRender组件显示中文的常见问题,提供了一套完整的实战解决方案。详细讲解了如何通过手动创建字体资产、精准控制字符集来优化性能,并重点介绍了通过调整材质中的Lerp节点参数(如设为-85, 92)来解决中文字体显示残缺和边缘模糊等核心难题,帮助开发者实现高效且美观的中文文本渲染。

weixin_28040125的博客 382

递归算法空间的缩减方法与尾递归

最近太忙,但是感觉有很多要写的东西,先列题目出来

一个健忘症患者的记忆备份 1114

三极管NPN与PNP的工作原理及快速识别技巧

本文深入浅出地解析了三极管NPN与PNP的核心工作原理。通过“水龙头”比喻,阐明其以小电流控制大电流的放大与开关本质。文章重点对比了NPN与PNP在电流方向、电位关系和控制逻辑上的根本区别,并提供了快速识别技巧与实用的选型、应用指南,帮助电子爱好者与工程师快速掌握这两种基础元件的关键知识。

neovim7hacker的博客 455

递归替换算法之尾递归

递归在很多时候被视为洪水猛兽。它的名声狼籍,好像永远和低效联系在一起。  其实,对一些如树的递归结构,递归算法是又自然又好用。  如果看看一些用来代替递归的技术,(汉诺塔的迭代算法不去说它,那是真正的算法的革命,除了佩服没啥好说的),一般来说只不过是自己模拟堆栈,编起来费劲,读起来费劲,维护起来更费劲。而模拟堆栈的效果,相比于简单的递归,好处在哪里呢?  1。不使用进程堆栈,不会耗尽堆栈空间

u010911350的专栏 2619

[QMT量化交易小白入门]-二十四、年化收益47%的全球核心资产轮动策略(含代码解析)

m_days = 25 #动量参考天数period=200m_days被设置为25,表示动量参考的天数为25天;period被设置为200,用于指定获取市场数据的周期长度。

木头大左的博客 2971

Android 车联网——CarAudioService介绍(六)

CarAudioService 是 Android Automotive OS 中的一个重要组件,用于管理车辆中的音频功能。它是 Android Auto 的一部分,负责处理车辆音频的播放、控制和路由。CarAudioService 使用标准的 Android 组件架构,基于 Binder 通信机制,提供了一组 API,用于管理车辆音频。它包括以下主要功能:音频路由管理:CarAudioService 可以让开发者控制音频的路由,即将音频发送到不同的输出设备,例如车辆的扬声器、耳机等。

小旭的专栏 3202

数据结构与算法 - 递归优化:尾递归与迭代转换

在深入优化之前,让我们先回顾一下递归的基本概念。递归是指一个函数直接或间接地调用自身来解决问题的过程。基础情况(Base Case):这是递归的终止条件。没有正确的基础情况,递归将无限进行下去,最终导致栈溢出。递归情况(Recursive Case):函数调用自身,但传入的是规模更小、更接近基础情况的参数。例子:计算阶乘考虑计算正整数n的阶乘n!。0!= 1n!(当 n > 0)// C语言示例// 基础情况return 1;// 递归情况# Python示例# 基础情况。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

【Scratch考级100图】图01-等级考试scratch绘 画正方形

一、案例介绍 小朋友们应该在数学课或者平时生活中有了解过正方形,正方形在我们生活中到处可见,那我们如果通过Scratch软件来绘制一个正方形呢,我们一起来学习一下吧,在舞台正中央绘制一个边长为200的正方形,要求: 1、围绕舞台中心绘制正多边形,均匀分布在四个象限中 2、正方形边长为200个单位,线条粗细、颜色自定 3、利用画笔绘制正方形,不能有多余的线条 二、案例演示 【Scratch案例演示】Scratch图1-画正方形 三、案例分析 当我们点击小绿旗启动程序后,舞台上会出现一个画

青少年编程学习指导 2670

算法分析与设计——递归与尾递归

什么是递归? 递归最恰当的比喻,就是查词典。我们使用的词典,本身就是递归,为了解释一个词,需要使用更多的词。当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词,可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个词的解释是你完全能看懂的,那么递归走到了尽头,然后你开始后退,逐个明白之前查过的每一个词,最终,你明白了最开始那个词的意思。 接下来,我们从递归的经典示例来理解。 斐波那契数列(Fibonacci Sequence): long fibonacci(i

炸鸡和薯条的博客 368

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

数据结构和算法|递归算法那些事(递归算法的时间复杂度、尾递归优化、斐波那契数列)

每次n-1,递归了n次时间复杂度是O(n),每次进行了一个乘法操作,乘法操作的时间复杂度一个常数项O(1),所以这份代码的时间复杂度是 n × 1 = O(n)。每次递归了做都是一次乘法操作,这也是一个常数项的操作,那么这个递归算法的时间复杂度才是真正的O(logn)。尾递归优化既可以是语言级别的,也可以是编译器级别的,我们的 C++ 就是编译器级别的尾递归优化。当前这棵二叉树就是求x的n次方,n为16的情况,n为16的时候,进行了多少次乘法运算呢?所以,如果是求 x 的 n 次方,那么时间复杂度就是。

糖炒栗子 1269

廖雪峰Python教程[完整版]

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

贪心算法及快速排序的尾递归优化版本

尾递归 如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。 当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活跃记录而不是在栈中去创建一个新...

彪悍的人生不需要解释! 753

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

算法中的递归和尾递归

文章目录1 递归2 尾递归 1 递归 对于很多编程初学者来说,递归算法是学习语言的最大障碍之一。很多人也是半懂不懂,结果学到很深的境地也会因为自己基础不好,导致发展太慢。 可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却不知道怎么使用。今天,我们就来说一说递归算法的使用。 什么是递归 递归,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。也就是说,递归算法是一种直接或者间接调用自身函数或者方法的算法。 通俗来说,递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调

上善若泪 1914

【算法设计-分治、动态规划】递归与尾递归

【算法设计-分治】递归与尾递归

Mount256的博客 923

算法之尾递归

//递归实现 int fabonacci(int n)//复杂度为指数级 { if(n==0) return 0; else if(n==1) return 1; else { return fabonacci(n-1)+fabonacci(n-2); } } //循环实现 int fabonacci2(int n)//复杂度:O(n) { int fab; int a=1

beatrice_g20的专栏 680

【算法】递归:递归优化之尾递归

文章首先会先通过斐波那契数列来复习在以往介绍的解决递归的方法,然后在通过这个例子去分析递归法的不足之处,最后将会介绍一下关于递归的优化策略,并举例实现。

qq_66725576的博客 4967
上一篇: 【JS】javascript 小技巧
下一篇: 【JS/读书随笔】JavaScript编程精解/Eloquent JavaScript:Chapter 2 函数
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值