递归算法

什么是尾递归

安稳与你 提交于 2020-02-26 14:35:13
递归算法想必大家都已经很熟悉了。递归算法虽然简单,但是容易导致一些性能问题,于是就有了尾递归这种优化算法。 首先我们先看看递归算法的性能问题是在哪里? 比如我们有一个常见的算法,叫做阶乘算法。 f ( x ) = 1 ⋅ 2 ⋅ 3 ⋯  ⁣ x f(x)=1\cdot2\cdot3\cdots\!x f ( x ) = 1 ⋅ 2 ⋅ 3 ⋯ x 他的递归实现是这样子的 KaTeX parse error: Unknown column alignment: 1 at position 15: \begin{array}{1̲}f(x)=x f(x-1)\… 实现代码如下 //C#实现 int Foo ( int x ) { if ( x == 1 ) { return 1 ; } return x * Foo ( x - 1 ) ; } #python 实现 def foo ( x ) : if ( x == 1 ) : return 1 return x * foo ( x - 1 ) 我们看到每次调用foo方法的时候,又会执行一次foo方法。 此时程序会将当前上下文压栈,计算出下一个foo的值,然后再出栈和x进行相乘 所以对于foo(3)的调用,整个栈的情况是这样的 KaTeX parse error: Unknown column alignment: 1 at

递归生成平衡二叉树

我的未来我决定 提交于 2020-02-26 10:36:11
生成平衡二叉树, 只需要知道节点的数目即可 生成方式采用中序遍历生成, 所以对应的中序遍历结果也是一个递增序列 基本算法思想为对于一个序列 [1, ...., n]对应的二叉树的根节点一定是棋中间节点, 而[1,...mid] mid [mid+1, ... n] 便是最基本的递归单元 class BNode { constructor(id, left, right) { this.id = id this.left = left this.right = right } get child() { return [this.left, this.right].filter(i => i) || [] } } function getBinTree(count) { // 从[st, ed) 构建二叉树 function buildTree(st, ed) { if(st===ed) return null let mid = Math.floor((st + ed + 1) / 2) if (st === ed - 1) { return new BNode(st) } let left = buildTree(st, mid ) // 注意这里需要mid + 1, 当前节点的id为mid let right = buildTree(mid + 1, ed) return

递归生成指定节点数目的树

主宰稳场 提交于 2020-02-26 10:14:45
做测试的时候需要用随机生成的树, 并且能指定节点个数 算法思路 一, 对一个数字进行分割 对数字N, 将其分割为最多M个数字之和 想象有N个小球排成一列, 有N-1个空挡, 随机找M-1个空挡放入挡板, 在第一个小球前面, 和最后一个小球后面也放上挡板, 这样就有了M+1个挡板, 相邻两个挡板之间的距离就是分离出来的树, 如果有两个挡板在同一位置, 说明, 分离出来的数字中含有0 二, 前序递归建树 对于递归函数而言, buildTree(n) 表示 返回有n个节点树, 则n===1时 直接返回一个节点, n>1 时表示该节点含有子树, 需要进行拆分后, 依次创建子节点, 由于采用前序生成, 所以前序遍历的id序列即为增序序列 function splitInt(n, count) { let list = [...Array(count - 1)] .map(_ => Math.floor(Math.random() * n)) .sort((a, b) => a - b) list.push(n) list.unshift(0) let res = [] for (let i = 1; i <= count; i++) { res.push(list[i] - list[i - 1]) } return res } class Node { constructor(id,

python递归——汉诺塔

…衆ロ難τιáo~ 提交于 2020-02-26 05:28:58
汉诺塔的传说 法国数学家 爱德华·卢卡斯 曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神 梵天 在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而 梵塔 、庙宇和众生也都将同归于尽。   不管这个传说的可信度有多大,如果考虑一下把64片金片,由一根针上移到另一根针上,并且 始终保持上小下大的顺序 。   这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明 f(n)=2^n-1 。n=64时, 假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:   18446744073709551615秒   这表明移完这些金片需要 5845.54亿年 以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命

关于递归方面的思想总结以及习题展示

こ雲淡風輕ζ 提交于 2020-02-25 20:01:07
汉诺塔游戏 * **【题目】** * 三个柱子,其中一个柱子全是由小到大的盘子 * 需要把这些盘子全部移动到另一个上并且顺序不变 * 要求:一次移动一个并且大的只可以在小的下面 *** 【算法思想】**: * 1,每次可以把第1~N-1个移到辅助柱子,第N个移动到目标柱子 * 2,然后将原始柱子作为辅助柱子,辅助柱子作为原始柱子 * 3,在进行第一步 *** 【总结】** * 学习递归要整体化思想把拆分后的一部分看作一个整体来处理 * 看到这个代码一直不明白,总是想把他代码套进去看一看 * 假如有4层的汉诺塔,把前3层作为整体就感觉一切都是那么顺其自然了 * 不必要担心前3层的操作,因为前3层在函数里面还会被分为第3层和前2层 * 所以说只需要将事物整体化,才可以看明白递归,才可以遇到问题想出递归代码 public class 汉诺塔游戏 { public static void main ( String [ ] args ) { String A = "A" , B = "B" , C = "C" ; printHanoiTower ( 4 , A , C , B ) ; } public static void printHanoiTower ( int N , String from , String to , String help ) { if ( N == 1 ) {

递归算法1

最后都变了- 提交于 2020-02-25 01:15:59
今天学了递归算法,下面的题目是对递归的理解 &1.问第n个学生多大 题目描述 例2.1有n个学生坐在一起 问第n个学生多少岁?他说比第n-1个学生大2岁. 问第n-1个学生岁数,他说比第n-2个学生大2岁. .......................................................... 问第2个学生,说比第1个学生大2岁. 最后问第1个学生,他说是10岁. 请问第n个学生多大? 输入 输入n 输出 输出第n个学生的年龄 样例输入 5 样例输出 18 思路:(关键点为第一个学生的年龄) 第1个学生年龄为10岁(往后每个学生比前一个学生大两岁) n age 1 10 (当n=1时age=10,这个条件要单独列出) 2 age(2-1)+2 3 age(3-1)+2 ... ... n age(n-1)+2 #include<iostream> using namespace std; int fac(int a) { int age; if(a==1){return age=10;} else return fac(a-1)+2; } int main() { int n; cin>>n; cout<<fac(n)<<endl; return 0; } &2.Fibonacci 题目描述 Ø例5.2 求Fibonacci数列问题。

递归函数-汉诺塔经典递归

非 Y 不嫁゛ 提交于 2020-02-25 01:15:06
前言 最近在读《JavaScript语言精粹》,对递归函数有了进一步的认识,希望总结下来: 递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决。递归函数就是会直接或者间接调用自身的一种函数,一般来说,一个递归函数调用自身去解决它的子问题。 "汉诺塔"经典递归问题 "汉诺塔"是印度的一个古老传说,也是程序设计中的经典的递归问题,是一个著名的益智游戏:   题目如下:     塔上有三根柱子和一套直径各不相同的空心圆盘,开始时源柱子上的所有圆盘都按从大到小的顺序排列。目标是通过每一次移动一个圆盘到另一根柱子上,最终把一堆圆盘移动到目标柱子上,过程中不允许把较大的圆盘放置在较小的圆盘上;      寻找规律(把所有的圆盘移动到C):   1)n(圆盘个数) == 1     第一次:1号盘 A -> C sum(移动次数) = 1   2)n == 2     第一次:1号盘 A -> B     第二次:2号盘 A -> C     第三次:1号盘 B -> C  sum = 3   3)n == 3     第一次:1号盘 A -> C     第二次:2号盘 A -> B     第三次:1号盘 C -> B     第四次:3号盘 A -> C     第五次:1号盘 B -> A     第六次:2号盘 B -> C     第七次

深入理解和设计递归技术的关键点的思考

馋奶兔 提交于 2020-02-25 01:11:42
如何理解递归,写出正确的递归程序,我觉得有几个关键点: 1.要从整体把握问题 递归的难点在于人脑并不适合去跟踪递归中自己调用自己的这个过程,这是因为人脑中不像计算机一样有一个可以记忆的堆栈, 但是不同的是人是会归纳的,而计算机只知道调用-返回。 因此,理解和设计递归,一定要从整体把握,数学归纳法和递归是一个对称的关系,数学归纳法不断的扩展自己,递归则是不断的分解 自己。递归中的递就是把主问题分解成子问题,归就是利用子问题的解逐步向上求解的过程了。 关键点是要善用数学归纳法里面的假设 ,就是假设子问题已经求解了,它得到的结果是什么,一旦这么想就是在从整体上把握问题,不必再去纠结细节。设计一个递归函数的时候,首先像普通函数一样设计一个算法框架,控制好程序逻辑,处理递归调用的时候假设是在调用一个其他的函数,这个函数已经设计好,你只需要知道他做什么事,然后返回什么就可以了,具体怎么做的,不需要去想,这似乎有些矛盾,因为这个函数本来就是自己,怎么不需要去想怎么做的呢?其实这就是递归难以理解的原因。所以必须先把细节放在一边,先确定好框架,然后再去处理细节。 2.关注函数的返回值是什么,如何利用子函数调用的返回值得到调用的返回值。 第一条里面设计好框架以后,然后我们就需要关注函数处理的细节了,这个细节包括流程分支,函数的返回值。 函数的返回值直接关系到函数是否正确执行

深度理解递归技术

懵懂的女人 提交于 2020-02-25 01:10:59
递归的使用条件:   存在一个递归调用的终止条件;   每次递归的调用必须越来越靠近这个条件;只有这样递归才会终止,否则是不能使用递归的! 总之,在你使用递归来处理问题之前必须首先考虑使用递归带来的好处是否能补偿   他所带来的代价! 否则,使用迭代算法会比递归算法要高效。 递归的基本原理:   1 每一次函数调用都会有一次返回.当程序流执行到某一级递归的结尾处时,它会转移到前一级递归继续执行.   2 递归函数中,位于递归调用前的语句和各级被调函数具有相同的顺序.如打印语句 #1 位于递归调用语句前,它按照递归调用的顺序被执行了 4 次.   3 每一级的函数调用都有自己的局部变量.   4 递归函数中,位于递归调用语句后的语句的执行顺序和各个被调用函数的顺序相反.    即位于递归函数入口前的语句,右外往里执行;位于递归函数入口后面的语句,由里往外执行。   5 虽然每一级递归有自己的变量,但是函数代码并不会得到复制.   6 递归函数中必须包含可以终止递归调用的语句. 一旦你理解了递归( 理解递归 , 关键是脑中有一幅代码的图片 , 函数执行到递归函数入口时 , 就扩充一段完全一样的代码 , 执行完扩充的代码并 return 后 , 继续执行前一次递归函数中递归函数入口后面的代码 ),阅读递归函数最容易的方法不是纠缠于它的执行过程,而是相信递归函数会顺利完成它的任务

数据结构与算法--递归(recursion)

送分小仙女□ 提交于 2020-02-24 02:02:38
递归的概念 简单的说: 递归就是方法自己调用自己 ,每次调用时传入不同的变量.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。 递归调用机制 我列举两个小案例,来帮助大家理解递归 1、打印问题 2、阶乘问题 //输出什么? public static void test(int n) { if (n > 2) { test(n - 1); } System.out.println("n=" + n); } //阶乘 public static int factorial(int n) { if (n == 1) { return 1; } else { return factorial(n - 1) * n; }} 3、使用图解说明递归的调用机制 递归能解决什么样的问题 1、各种数学问题如: 8皇后问题 , 汉诺塔, 阶乘问题, 迷宫问题, 球和篮子的问题(google编程大赛) 2、各种算法中也会使用到递归,比如快排,归并排序,二分查找,分治算法等. 3、将用栈解决的问题-->第归代码比较简洁 递归需要遵守的重要规则 1)执行一个方法时,就创建一个新的受保护的独立空间(栈空间) 2)方法的局部变量是独立的,不会相互影响, 比如n变量 3)如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据. 4)递归 必须向退出递归的条件逼近 ,否则就是无限递归