递归算法

二叉树先序、中序、后序、层次遍历递归以及非递归算法实现

ぐ巨炮叔叔 提交于 2019-11-27 15:59:52
最近写了一下关于二叉树的三种遍历算法的递归以及非递归实现,以及层次遍历算法实现 先序遍历递归实现 /** * 先序遍历,根》左》右 */ public void beforeTraverse ( TreeNode root ) { if ( root == null ) { return ; } System . out . print ( root . val + "->" ) ; if ( root . left != null ) { beforeTraverse ( root . left ) ; } if ( root . right != null ) { beforeTraverse ( root . right ) ; } } 先序遍历非递归实现 /** * 通过栈遍历二叉树,先序(思想就是:入栈即记录) */ public List < String > beforeTraverseByStack ( TreeNode root ) { List < String > list = new ArrayList < > ( ) ; // 接受结果 if ( root == null ) { return list ; } Stack < TreeNode > stack = new Stack < > ( ) ; // 先序遍历(根 》左 》右),先遍历所有左结点

JavaScript函数尾调用与尾递归

半世苍凉 提交于 2019-11-27 15:13:48
什么是函数尾调用和尾递归 函数尾调用与尾递归的应用 一、什么是函数的尾调用和尾递归 函数尾调用就是指函数的最后一步是调用另一个函数。 1 //函数尾调用示例一 2 function foo(x){ 3 return g(x); 4 } 5 //函数尾调用示例二 6 function fun(x){ 7 if(x > 0){ 8 return g(x); 9 } 10 return y(x); 11 } 调用最后一步和最后一行代码的区别,最后一步的代码并不一定会在最后一行,比如示例二。还有下面这一种不能叫做函数尾调用: 1 // 下面这种情况不叫做函数尾调用 2 function fu(x){ 3 var y = 10 * x; 4 g(y); 5 } 为什么这种情况不叫作函数的尾调用呢?原因很简单,因为函数执行的最后一步是return指令,这个指令有两个功能,第一个功能是结束当前函数执行,第二个功能是将指令后面的数据传递出去(函数返回值)。而这个return指令不管有没有声明都会执行,没有声明的情况下返回的数据是undefined,所以上面的代码实际上是以下结构: 1 function fu(x){ 2 var y = 10 * x; 3 g(y); 4 return undefined; 5 } return指令是先关闭函数,然后再返回数据。说到这里,就会引发一个问题出来

8.14 函数递归

倾然丶 夕夏残阳落幕 提交于 2019-11-27 07:59:00
8.14 函数递归 函数的嵌套调用是:函数嵌套函数。函数的递归调用:它是一种特殊的嵌套调用,但是它在调用一个函数的过程中,又直接或间接地调用了它自身。 递归必须要有两个明确的阶段: 递推:一层一层递归调用下去, 进入下一层递归的问题规模都将会减小 回溯: 递归必须要有一个明确的结束条件 ,在满足该条件开始一层一层回溯。 递归的精髓在于通过不断地重复逼近一个最终的结果。 例如,已知一个人的年龄为16,后面每个人的年龄都是前一个人的年龄+2,求第n个人的年龄: age = 16 def age_func(n): global age if n == 0: return age age += 2 return age_func(n-1) print(age_func(5)) # 26 ''' age_func(5) --> age = 18 --> return age_func(4) # return 26 age_func(4) --> age = 20 --> return age_func(3) age_func(3) --> age = 22 --> return age_func(2) age_func(2) --> age = 24 --> return age_func(1) == return age_func(0) == return age == return 26

Python学习day15-函数进阶(3)

廉价感情. 提交于 2019-11-27 07:56:42
/*--> */ /*--> */ Python学习day15-函数进阶(3) 函数递归 递归的调用 递归的两个阶段 递归的本质 递归最好的体现之一,汉诺塔问题 内置函数 面向过程编程 Python学习day15-函数进阶(3) 函数递归 递归,很多语言中都会有这个概念,或者说这应该是一种思想,可以比较简便的解决一些无法直接得到答案的算法问题。 递归的调用 递归的调用其实就是函数的一种嵌套的调用,但是它在调用一个函数的时候又直接或间接地调用了它自身,以此形成一种循环调用的关系,直到接近或达到我们设置的条件为止。 递归的两个阶段 递归一般要有的两个比较明确的阶段是: 递推:一层一层调用下去,进入下一层递归的问题的规模一定是变小的,不然递归会无限调用下去直到报错。 回溯:即递归必须有一个明确的结束条件,在满足该结束条件之后递归会一层一层的回溯,在此之前递归会一层一层的调用,占用新的内存空间,不会释放。 所以递归的精髓就在于通过不断的重复逼近一个最终的结果。 递归的本质 递归的本质就是干重复的事情,那么仅仅是普通的重复,为什么不直接用循环呢,普通的循环更节省空间和时间。 下例中可以解释这个问题: x 1 lis = [1,[2,[3,[4,[5,[6,]]]]]] 2 ​ 3 def tell (lis): 4 for i in lis: 5 if type(i) is list: 6

二分查找(递归和非递归)

[亡魂溺海] 提交于 2019-11-27 07:21:52
二分算法步骤描述 前提:有序数组中查找关键词所在的位置 ① 首先确定整个查找区间的中间位置 mid = strat+(end-strat)/2 ② 用待查关键字key值与中间位置的关键字值进行比较; 若相等,则查找成功 若大于,则在后(右)半个区域继续进行折半查找 若小于,则在前(左)半个区域继续进行折半查找 ③ 对确定的缩小区域再按折半公式,重复上述步骤。 一、非递归二分查找算法(用while循环判断) public static int search(int key,int[] arr){ int start=0; int end=arr.length-1; while(start<=end){ int mid=start+(end-start)/2; if(key<arr[mid]){ end=mid-1; }else if(key>arr[mid]){ start=mid+1; }else{ return mid; } } return -1; } 二、递归二分查找算法 public static int search2(int key,int[] arr,int start,int end){ if(start >end){ return -1; } int mid=start+(end-start)/2; if(key<arr[mid]){ return search2

【算法008】二叉树查找

前提是你 提交于 2019-11-27 05:21:01
代码: package com.example.chyer.demo; import java.util.Stack; public class Test { private String v; private Test left; private Test right; public static void main(String[] args) { // 初始化二叉树 Test parent = new Test(); parent.v = "4"; parent.left = new Test(); parent.left.v = "2"; parent.left.left = new Test(); parent.left.left.v = "1"; parent.left.right = new Test(); parent.left.right.v = "3"; parent.right = new Test(); parent.right.v = "6"; parent.right.left = new Test(); parent.right.left.v = "5"; System.out.println("先序遍历:"); parent.preOrder(); System.out.println("中序遍历:"); parent.infixOrder();

算法设计

不羁的心 提交于 2019-11-27 03:55:47
一、分治法 递归,找最大值最小值,整数相乘,归并排序,快速排序,线性时间选择,最近点对问题 二、动态规划   0-1背包问题 ,矩阵相乘问题,装配线调度问题,最长公共子序列,最优二分检索树,凸多边形最优三角剖分 三、贪心法   背包问题,活动选择问题,哈夫曼编码,最小生成树算法(Kruskal 和 Prim) 四、回溯法   n皇后问题,子集和数问题,0-1背包问题,旅行商问题,着色问题 五、图算法   图的表示,广度优先搜索,Dijkstra算法 来源: https://www.cnblogs.com/eaglezb/p/11343106.html

递归与迭代

只愿长相守 提交于 2019-11-27 02:05:35
( 递推算法的首要问题是得到相邻的数据项间的关系(即递推关系)。递推算法避开了求通项公项的麻烦,把一个复杂的问题的求解,分解成了连续的若干步简单运算。一般说来,可以将递推算法看成是一种特殊的迭代算法。) 递归(调用本身)与迭代(新值换旧值)都是基于控制结构:迭代用重复结构,而递归用选择结构。递归与迭代都涉及重复:迭代显式使用重复结构,而递归通过重复函数调用实现重复。递归与迭代都涉及终止测试:迭代在循环条件失败时终止,递归在遇到基本情况时终止。使用计数器控制重复的迭代和递归都逐渐到达终止点:迭代一直修改计数器,直到计数器值使循环条件失败;递归不断产生最初问题的简化副本,直到达到基本情况。迭代和递归过程都可以无限进行:如果循环条件测试永远不变成false,则迭代发生无限循环;如果递归永远无法回推到基本情况,则发生无穷递归。 递归有许多缺点,它重复调用机制,因此重复函数调用的开销很大,将占用很长的处理器时间和大量的内存空间。每次递归调用都要生成函数的另一个副本(实际上只是函数变量的另一个副本).从而消耗大量内存空间。迭代通常发生在函数内,因此没有重复调用函数和多余内存赋值的开销。那么,为什么选择递归呢? --------------------------------------------------------------------------- 摘要:在算法的分析与设计中

递归与迭代

别说谁变了你拦得住时间么 提交于 2019-11-27 02:05:12
  对于递归与迭代的关系,也许很多人都不是很清晰,其实本质上递归与迭代时间复杂度方面是等价的(在不考虑函数调用开销和函数调用产生的堆栈开销),而递归主要是每递归一次,都会在栈中分配函数的空间,造成空间消耗过大,而且是与递归的深度成正比。从实际上说,所有的迭代可以转换为递归,但递归不一定可以转换为迭代。以下为引用: < 作者: Enoch Wang 引用自: http://chinawangquan.spaces.live.com > 所谓递归,简而言之就是应用程序自身调用自身,以实现层次数据结构的查询和访问。 递归的使用可以使代码更简洁清晰,可读性更好(对于初学者到不见得),但由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多,而且,如果递归深度太大,可能系统资源会不够用。 往往有这样的观点:能不用递归就不用递归,递归都可以用迭代来代替。 诚然,在理论上,递归和迭代在时间复杂度方面是等价的(在不考虑函数调用开销和函数调用产生的堆栈开销),但实际上递归确实效率比迭代低,既然这样,递归没有任何优势,那么是不是就,没有使用递归的必要了,那递归的存在有何意义呢? 万物的存在是需要时间的检验的,递归没有被历史所埋没,即有存在的理由。从理论上说,所有的递归函数都可以转换为迭代函数,反之亦然,然而代价通常都是比较高的。但从算法结构来说,递归声明的结构并不总能够转换为迭代结构

递归与迭代

自闭症网瘾萝莉.ら 提交于 2019-11-27 02:04:57
关于c语言部分函数的一些总结和注意事项: 递归是一种强有力的技巧,但是和其他技巧一样,它也可能被误用。这里就有一个例子。阶乘的定义往往就是以递归的形式描述的。factorial(n)=1,n<=0; factorial(n)=n*factorial(n-1),n>0; 这个定义同时具备了递归所需要的两个特性:1、存在限制条件,当符合这个条件时递归便不再继续;2、每次递归调用之后越来越接近这个限制条件。用这种方式定义阶乘往往引导人们使用递归来实现阶乘函数。程序如下所示: 1 //用递归方法计算n的阶乘 2 3 long factorial(int n) 4 5 { 6 7 if(n<=0) 8 9 return 1;10 11 else12 13 return n*factorial(n-1);14 15 } 但它不是递归的良好用法。为什么呢?因为递归函数调用将涉及一些运行时开销——参数必须压到堆栈中,为局部变量分配内存空间(所有递归均如此,并非特指这个例子),寄存器的值必须保存等。当递归函数的每次调用返回时,上述这些操作必须还原,恢复成原来的样子。所以,基于这些开销,对于这个程序而言,它并没有简化问题的解决方案。下面这个函数是尾部递归的一个例子,由于函数在递归调用返回后不再执行任何任务,所以尾部递归可以很方便的转换成一个简单循环,完成相同的任务 ,程序效率更为有效。 1 /