尾递归

递归与尾递归

送分小仙女□ 提交于 2020-01-29 16:34:12
1.递归 递归是一个函数直接或间接地调用自身,是为直接或间接递归。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。用递归需要注意以下两点: (1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。 递归一般用于解决三类问题:   (1)数据的定义是按递归定义的。(Fibonacci函数,n的阶乘)   (2)问题解法按递归实现。(回溯)   (3)数据的结构形式是按递归定义的。(二叉树的遍历,图的搜索) 递归的缺点:   递归解题 相对常用的算法如普通循环等,运行效率较低 。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成 栈溢出 。 代码: int FibonacciRecursive(int n) { if( n < 2) return n; return (FibonacciRecursive(n-1)+FibonacciRecursive(n-2)); } 递归写的代码非常容易懂,完全是根据函数的条件进行选择计算机步骤。例如现在要计算n=5时的值,递归调用过程如下图所示: 2.尾递归 尾递归就是从最后开始计算,

SICP学习笔记(1.2.1 ~ 1.2.2)

 ̄綄美尐妖づ 提交于 2020-01-27 20:12:42
SICP学习笔记(1.2.1 ~ 1.2.2) 周银辉 1, 递归过程 和 递归计算过程 在学习SICP前我还没注意过有这样的一个区分,因为我们始终停留在语法表面上的“递归过程(recursive procedure)”,而没有去理解其实质是否是“递归计算过程(recursive process)”。 递归过程:从语法书写层面上而言的,在过程的定义中,其直接或间接地引用该过程本身。 比如 F{F}或者 F{G{F}} 递归计算过程:从实际运算层面上而言的,一个在语法上按照递归过程书写的函数其在运算时可能是按照递归的方式也可能是按照迭代的方式进行的。这取决于解释器或编译器本身是否有对“递归”进行优化,比如Scheme解释器是“严格尾递归”的, 而C#之类的,即便在语法形式上是"尾递归"的,但其仍然不能被编译成迭代计算过程,当然,你可以使用for,while等. 要检测出一个递归过程在计算时到底是按照递归方式还是按照迭代方式进行的,非常容易,只要将其进行深度递归或无限次递归,如果Stack Overflow了,那么是按照递归方式计算的,仅仅是一个死循环似的不停计算但没有栈溢出,那么是按照迭代方式计算的。一般而言函数式编程语言(Scheme,Haskell等), 会按照迭代方式进行计算;命令式编程语言(C++,C#,Java等)会按照递归方式进行计算。 2,迭代计算过程 和 递归计算过程

一般递归&尾递归&循环递归

旧街凉风 提交于 2020-01-17 05:27:32
阶乘的一般递归 int factorial(int n){ if(n<=1) return 1; return (n*factorial(n-1)); } 阶乘的尾递归 int factorial_tail(int n,int res){ if(n<=1) return res; return factorial_tail(n-1,n*res); } 阶乘的迭代形式 int factorial_loop(int n){ int r=1; for(int i=1;i<=n;i++){ r=r*i; return r; } 斐波那契数列递归 斐波那契数列的一般递归 int fibonacci(int n){ if(n<=3) return 1; else{ return fibonacci(n-1)+fibonacci(n-2); } } 斐波那契数列的尾递归 int fibonacci_tail(int n,int acc1,int acc2){ if(n<2) return acc1; else return fibonacci(n-1,acc2,acc1+acc2); } } 斐波那契数列的循环递归 int fibonacci_loop(int n){ int a=0; int b=1; if(n==1) return 1; if(n==2) return 1; for(int

等差数列,for循环,递归和尾递归的对比

╄→尐↘猪︶ㄣ 提交于 2020-01-14 16:03:35
生活中,如果1+2+3+4.....+100,大家基本上都会用等差数列计算,如果有人从1开始加,不是傻就是白X,那么程序中呢,是不是也是这样。今天无意中看到了尾递归,以前也写过,但是不知道这个专业名词,今天写一下对比下性能问题。 今天主要是看到了尾递归,所以联想到了这些,写下这篇文章,其中也把Benchmark (Nuget上的BenchmarkDotNet)的基准测试用了下,感觉比较好用,赞。Benchmark 需要在release下运行。 原则上所有的递归操作,都可以写成循环操作。尾递归是指,在函数返回的时候,调用自身本身,并且return语句不能包含表达式。这样编译器或者解释器就可以把尾递归做优化,试运行速度更快。 测试类 public class TestClass { /// <summary> /// for循环 /// </summary> /// <param name="n"></param> /// <param name="counter"></param> /// <returns></returns> public int TestFor(int n) { int s = 1; for (int i = 2; i < n + 1; i++) { s = s + i; } return s; } /// <summary> /// 等差数列 /// <

尾递归是个什么鬼

自古美人都是妖i 提交于 2019-12-26 08:49:21
“普通程序员使用迭代,天才程序员使用递归” 大家都说递归好用,却也都在抱怨递归过程占用内存的弊病。   以上是博主学习编程以来一直困惑的问题,能不能使用外部给的一个储存空间,使用一种近似for循环的机制解决递归爆栈,但是总有一些细节感觉不妥。这过程中内存问过一些比我牛的大佬,仍没能得以解决,知道在《图解算法》中看到“尾递归”这三个字。。。 聊聊尾递归,说尾递归,首先要说说尾调用和递归这两个小概念:   “尾调用”是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。这种情形下该调用位置为尾位置。(维基百科这样解释)   “递归”就是程序不断的调用自己本身,递归函数调用顺序:         a.调用开始前,调用方(或函数本身)会往栈上压相关的数据,参数,返回地址,局部变量等         b.执行函数         c.清理栈上相关的数据,返回   “尾递归”:顾名思义,就是兼顾“尾调用”和“递归”两者优点的一种不同的“递归”。这一种依赖于编译器的帮助实现的递归方式,并不是每一种语言都可以实现。       C语言可以实现,python就不能实现这种很奇妙的递归方式。 尾递归了解了,防止递归爆栈的方式也知道了,但是python中的递归内存问题还是本人的困惑,希望有一天,能和龟叔级别的人物聊聊类似的问题的解决方案。 努力更新中。。。

Python大一上总结

自作多情 提交于 2019-12-25 01:10:15
大一菜鸡Python总结 初次接触Python的一些入门知识 字符串及数据类型等 Python程序控制结构 想要写出一个比较好的程序控制结构,画流程图是非常重要的。想必在高中大家都有所借出流程图吧。以下是 流程图的7个基本元素 运用好基本元素就可以画出一个这样的流程图啦。 分支结构 程序由三种基本结构组成:顺序结构、分支结构、循环结构,这些基本结构都有一个入口和一个出口。任何程序都由这三种基本结构组合而成。 顺序结构 是程序按照线性顺序依次执行的一种运行方式,其中语句块S1和语句块S2表示一个或一组顺序执行的语句 2.分支结构 是程序根据条件判断结果而选择不同向前执行路径的一种运行方式,包括单分支结构和二分支结构。由二分支结构会组合形成多分支结构 3.循环结构 是程序根据条件判断结果向后反复执行的一种运行方式,根据循环体触发条件不同,包括条件循环和遍历循环结构 Python分支结构 共有单分支结构、二分支结构、多分支结构,其中分支结构还可以加入条件判断及组合 单分支结构 if <条件> : <语句块> 2.二分支结构 if <条件> : <语句块1> else : <语句块2> 3.多分支结构 f <条件1> : <语句块1> elif <条件2> : <语句块2> …… else : <语句块N> 条件判断及组合 用于条件组合的三个保留字 Python循环结构

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; }

python 递归函数

吃可爱长大的小学妹 提交于 2019-12-06 14:57:11
python学习笔记,特做记录,分享给大家,希望对大家有所帮助。 在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。 举个例子,我们来计算阶乘n! = 1 x 2 x 3 x … x n,用函数fact(n)表示,可以看出: fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n 所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。 于是,fact(n)用递归的方式写出来就是: def fact(n): if n==1: return 1 return n * fact(n - 1) print(fact(1)) print(fact(5)) print(fact(100)) 上面就是一个递归函数。可以试试,运行结果如下: 1 120 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 Process finished with exit code 0

Java小白常问的问题大全

☆樱花仙子☆ 提交于 2019-12-05 03:08:21
Java小白在初学Java时都会遇到各种各样的问题,小编来总结一下一些常见的问题。比如,可以用%除以一个小数吗?a+=b和a=a+b的效果有区别吗?声明一个数组为什么需要花费大量时间?为什么Java库不用随机pivot方式的快速排序? 如果有想学习java的同学,可来我们的java技术学习QQ群的哦:745446493里面免费送整套系统的java教程! 基本数据类型 1.我可以用%除以一个小数吗? 当然可以。比如,如果angle是一个非负数,那么angle%(2*Math.PI)就会把angle转换到0到2π之间。 2.当ab都是基本类型变量时,a+=b和a=a+b的效果有区别吗? 当a和b的类型不同时,那两条语句的效果就可能有区别。a+=b等同于a=(int)(a+b),这种情况下可以是a是int型,b是float型。但是同等情况下a=a+b就会编译报错。 3.为什么-0/3结果是0,而-0.0 /3.0结果是-0.0?(注意后边的结果0带负号) 在Java里,整数是用补码表示的。在补码中0只有一种表示方法。另一方面,浮点数则是用IEEE标准表示的,对于0有两种表示方法,0和-0。 条件语句和循环语句 1.为什么判断字符串相等不能使用==? 这反映了基础类型(int,double,boolean)和引用类型(String)的区别。 2.有没有在什么情况下

尾递归实现斐波那契数列

一笑奈何 提交于 2019-12-03 10:04:17
一、斐波那契数列 斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368...... 二、递归算法 1. 代码 public int fib(int n){ if(n==1 || n==2){ return 1; } return fib(n-1)+fib(n-2); } 2. 缺点:多次计算重复的fib(n),性能低,一般只用于说明递归算法 三、改进:空间换时间,把计算出来的fib(n)存储起来,不用重复计算,空间复杂度O(n) public int fib(int n){ int[] array=new int[n]; array[0]=1; array[1]=1; for(int i=2;i<n;i++){ array[i]=array[i-1]+array[i-2]; } return array[n-1]; } 四、再次改进,空间减少到O(1),只存储3个数:前两个数和前两个数相加计算出来的结果 public int fib(int n){ int first=1; int second=2; int third=3; for(int i=3;i<=n;i++){ third=first