递归调用

递归如何转换为非递归

大城市里の小女人 提交于 2019-12-21 04:24:50
递归 算法实际上是一种分而治之的方法,它把复杂问题分解为简单问题来求解。递归的特点包括:递归过程简洁、易编、易懂;递归过程效率低、重复计算多。 考虑递归的执行效率低,可以尝试将递归过程转换为非递归过程。本文就是来探讨怎么转换的。 将递归算法转换为非递归算法有两种方法,一种是直接求值(迭代/循环),不需要回溯;另一种是不能直接求值,需要回溯。前者使用一些变量保存中间结果,称为直接转换法;后者使用栈保存中间结果,称为间接转换法,下面分别讨论这两种方法。 一、直接转换法 直接转换法通常用来消除尾递归和单向递归,将递归结构用循环结构来替代。 1.单向递归 简单的说是指递归的过程总是朝着一个方向进行,如果函数1调用了函数2,而函数2又调用了函数1,则这种情况不属于单向递归。斐波那契数列(单向递归)的递归求解可转用一个迭代法实现。 斐波那契数列的递归求解: int Fib(int n) {   if(n <= 1) return n;   else return Fib(n - 1) + Fib(n - 2); } 转换为迭代求解过程: int Fib(int n) {    if(n <= 1) return n;   int twoBack = 0;    int oneBack = 1;    int cur;   for(int i = 2;i < = n; i++) {    cur

递归调用

左心房为你撑大大i 提交于 2019-12-21 04:11:12
1.组合式公式 设计思想 实验要求输入两个数求组合数,首先要输这两个数才能进行程序,输入后,根据组合数公式中全是阶乘,使用递归比较方便,n!=n*(n-1)*......1,递归中返回n*zuheshu(n-1),实现阶乘,最后调用阶乘函数,输出就完成程序。 程序流程图 实验源代码 import java.util.Scanner; public class Sz { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner input=new Scanner(System.in); int a; int b; int c; //定义所需的三个变量 System.out.println("输入组合数公式所需的数:"); a=input.nextInt(); b=input.nextInt(); //对要计算的两个变量进行赋值。 while(a==0||a<=b) { System.out.println("无法计算,重新输入"); } //判断底下的除数是否可除 c=zuheshu(a)/(zuheshu(b)*zuheshu(a-b));//用递归函数对a,b进行赋值计算后传给c。 System.out.println("组合数为

递归调用

混江龙づ霸主 提交于 2019-12-21 01:48:45
def fact(n): if n == 1: return 1 return n * fact(n-1) print(fact(1)) print(fact(5)) print(fact(100)) #递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。 #使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000): #print(fact(1000)) 这一句会出现错误,递归实际上是在栈中进行的,栈空间有限,因而递归次数不能太多 #解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。 #尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况 def fact2(): return fact_iter(n, 1) def fact_iter(Inum, product): if num = 1: return product

ES6 入门系列 (三) 尾递归

送分小仙女□ 提交于 2019-12-20 02:16:36
  递归我们不陌生,   那什么是尾递归呢?   为什么要用尾递归呢?   尾递归怎么用呢?   带着这三个问题我们来了解它, 我们知道递归非常耗费内存,一不小心就会发生‘栈溢出’, 相信你一定遇到过这个错误: stack overflow, 尾递归就是用来优化递归的这个问题的。   尾递归的定义: 在函数的最后一步返回自身,也就是显示地return自身就称为尾递归。对于尾递归来说, 由于只存在一个调用帧,所以永远不会发生‘栈溢出’。   我们来举例说明尾递归的好处: 比如计算n的阶乘, 我们首先想到找规律, n的阶乘等于n* (n-1)的阶乘 找出口1的阶乘等于1 然后我们就很自然的用递归写出 function jieCheng(n) { if (n===1) { return 1 } return n * jieCheng(n -1); } const result = jieCheng(5); console.log(result); // 120 很自然, so easy有木有,    but, 这样我们每递归一次,上一次的调用记录还保存着, 也就是说我们计算n的阶乘最多要保存n个调用记录,复杂度为O(n).    改成尾递归:     function weiJieCheng(n, total=1) { if (n === 1) { return total; }

第十二次-递归下降语法分析

那年仲夏 提交于 2019-12-18 12:30:08
一、实验目的: 利用C语言编制递归下降分析程序,并对简单语言进行语法分析。 编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。 二、实验原理 每个非终结符都对应一个子程序。 该子程序根据下一个输入符号(SELECT集)来确定按照哪一个产生式进行处理,再根据该产生式的右端: 每遇到一个终结符,则判断当前读入的单词是否与该终结符相匹配,若匹配,再读取下一个单词继续分析;不匹配,则进行出错处理 每遇到一个非终结符,则调用相应的子程序 三、实验要求说明 输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”,并指出语法错误的类型及位置。 例如: 输入begin a:=9;x:=2*3;b:=a+x end # 输出success 输入x:=a+b*c end # 输出‘end' error 四、实验步骤 1.待分析的语言的语法(参考P90) 2.将其改为文法表示,至少包含 –语句 –条件 –表达式 3. 消除其左递归 4. 提取公共左因子 5. SELECT集计算 6. LL(1)文法判断 7. 递归下降分析程序 解: #include<stdio.h> #include <iostream> #include<string.h> using namespace std; char *reserved

递归

為{幸葍}努か 提交于 2019-12-18 06:51:38
递归的概念 函数可以自己调用自己,称为递归调用。虽然可以写出递归,但是我并不知道它是如何得出结果。 函数的递归调用 方法: 1.首先去找临界值,就是无需计算,就能获得的值 2.找这一次和上一次的关系 3.假设当前函数已经可以使用了,调用自身计算上一次的运行结果,再写出这次的运行结果 例如计算1加到n的和 sum(100) = sum(99) + 100; sum(n) = sum(n - 1) + n; 需要注意的是,递归会在短时间内,使内存剧增。 function sum(n){ if (n == 1) { return 1; } return sum(n - 1) + n; } alert(sum(100)); 结果为5050。 运行特点: 1.必须有参数 2.必须有return 实例: 通过递归,打印n个hello world function print(n){//必须有参数 if (n == 0) { return;//必须有return } document.write("hello world<br>"); return print(n - 1); } print(10); 判断一个函数是否为闰年 参数:年份  返回值:是否为闰年 function leapYear(){ var x = new Date().getYear(); if (x % 400 == 0 |

数据结构与算法--栈、队列(栈)

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-18 02:38:31
hello,everybody. 我们又见面了,这次我们一起来学习数据结构中,非常有意思的两种结构—Stack ,Queue. 首先来学习一下栈: 栈: 限定只在表尾进行删除插入操作的线性表。 顾名思义,栈是一种特殊的线性表。它特殊在什么地方呢?它只能在表尾进行插入或删除操作,又就意味着,它只能是先进后出。给大家举个现实中,利用栈的例子。我们都用浏览器浏览过网页,我们对浏览器的前进后退按钮一定都不陌生。当我们打开第一个网页时,有一个图片链接,于是我们又跳到了第二个网页。此时,又有一个文字链接,我们又跳到了第三个网页。此时,我点击浏览器的后退按钮,我们会回到第二个网页。再点击浏览器的后退按钮,我们又跑到了第一个网页。是不是最先打开的第一个网页,是最后一个恢复的?是不是,先进后出? 看来,我们在学习第二章线性表时,付出的心血没有白费。看看,我在学习栈与队列时,感到很轻松,因为它讲的一些概念,我都掌握了。所以,我们在学习知识时,一定要踏实,耐心。付出一定会有回报的,你用心付出,回报巨大,回报明显。你不用心付出,回报微小,回报不明显。你不付出,只是随意看看,那么当别人说起这些知识时,你也可以装下B。所以,付出是有回报的。只是为了,回报巨大,回报明显,我们需要用心,态度要端正。 我们把允许删除的一端称为栈顶(Top),另一端称为栈底(Bottom). 不含任何数据元素的栈称为空栈

递归

一个人想着一个人 提交于 2019-12-17 06:09:24
1、 有递归的结束时处理 2、  字节调用自己 好处: 不需要知道循环次数 弊端: 递归次数过多,容易导致栈内存溢出 public class test4_digui { public static void main(String[] args) { System.out.println(jiecheng(5)); } public static int jiecheng(int n) { if (n == 1) { return n; } else { return n*jiecheng(n-1); } } 来源: https://www.cnblogs.com/yaobiluo/p/11312527.html

递归

人盡茶涼 提交于 2019-12-17 04:13:29
# include <stdio.h> int jisuan ( int n ) ; int main ( ) { int n ; scanf ( "%d" , & n ) ; printf ( "n=%d,age=%d" , n , jisuan ( n ) ) ; } int jisuan ( int n ) { if ( n == 1 ) { return 10 ; } else return jisuan ( n - 1 ) + 2 ; } //递归函数的函数调用,首先一 定要有基线情况,返回值的类型处理和之前的相类似; //递归就是在函数内部调用本身函数的过程,最后返回一个结果 //基线情况就是问题元素允许出现的最简单的可能值 //通常情况为if(…) //{ // return a(a就是最简单情况的答案) //} //确定基线情况后再来编写数据较多,元素较多的计算方法,此时调用函数本身 //并且计算的方法为先算题目要求的最后一个,如阶乘:fact(n-1)*n; //如此题:jisuan(n-1)+2; //因为调用是从最后一个数据往前逐个调用,直到遇到基线情况,然后逐步返回到上一步,一层一层的返回 //直到最终返回到第n种情况后从函数返回到主函数 来源: CSDN 作者: zhengrui23751 链接: https://blog.csdn.net

递归——自己调用自己

ⅰ亾dé卋堺 提交于 2019-12-17 00:49:09
程序的入口为main方法,方法都是压栈执行,没有创建对象的情况下则用不到堆内存,只涉及到栈内存和方法区; “ return ” 语句为结束方法; 返回值到方法调用处; 递归——自己调用自己; 栈内存分析: 递归要有条件并且次数不能太多: 运行结果: 其中,栈内存一直在变化,可能每次都不一样,当方法执行了11157次时候发生了栈内存溢出异常; 构造方法不能递归操作: 来源: https://www.cnblogs.com/wmqiang/p/10731094.html