递归调用

汉诺塔(Hanoi)问题递归&非递归的C++实现及总结

时间秒杀一切 提交于 2019-12-03 03:21:24
汉诺塔(Hanoi)问题递归&非递归的C++实现及总结 由于刚入门不算很久,所以就那汉诺塔这种简单问题来练下手啦~~ 【汉诺塔问题内容】 (虽然路人皆知但还是写一下好了。。。)   相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。   详细的背景可以去 百度百科 自己看~~ 【递归实现】 //汉诺塔问题最简单最经典的解决方法当然是递归解决啦~~ #include <iostream> using namespace std ; void hanoi( int n, int a, int b, int c) { if (n > 0 ) { hanoi(n- 1 , a, c, b); cout << "move " << a << " to " << b << endl; hanoi(n- 1 , c, b, a); } } int main() { int n; cin >> n; hanoi(n, 1 , 2 , 3 ); return 0 ; } //非常简单就搞定了

《程序员的数学》:汉诺塔问题(Hanoi问题)的递归算法与非递归算法总结

佐手、 提交于 2019-12-03 03:18:05
如果对汉诺塔算法的理解有困难,建议查看 《程序员的数学》:第6章 递归——自己定义自己 这一章作者详细用图形介绍了汉诺塔递归算法,便于理解,茅塞顿开! 现对该算法从递归和非递归两个方面做如下总结: 1.递归算法分析 如下, 设A上有n个盘子。 如果n=1,则将圆盘从A直接移动到C。 如果n=2,则: (1)将A上的n-1(等于1)个圆盘移到B上; (2)再将A上的一个圆盘移到C上; (3)最后将B上的n-1(等于1)个圆盘移到C上。 如果n=3,则: A)将A上的n-1(等于2,令其为n`)个圆盘移到B(借助于C),步骤如下: (1)将A上的n`-1(等于1)个圆盘移到C上。 (2)将A上的一个圆盘移到B。 (3)将C上的n`-1(等于1)个圆盘移到B。 B)将A上的一个圆盘移到C。 C)将B上的n-1(等于2,令其为n`)个圆盘移到C(借助A),步骤如下: (1)将B上的n`-1(等于1)个圆盘移到A。 (2)将B上的一个盘子移到C。 (3)将A上的n`-1(等于1)个圆盘移到C。到此,完成了三个圆盘的移动过程。 从上面分析可以看出,当n大于等于2时, 移动的过程可分解为三个步骤: 第一步 把A上的n-1个圆盘移到B上; 第二步 把A上的一个圆盘移到C上; 第三步 把B上的n-1个圆盘移到C上; 其中第一步和第三步是类同的。 当n=3时,第一步和第三步又分解为类同的三步,即把n`

归和迭代的区别、联系、优缺点

只愿长相守 提交于 2019-12-03 02:48:19
1.概念区分 递归 的基本概念: 程序调用自身的编程技巧称为递归,是函数自己调用自己. 一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合. 使用递归要注意的有两点: 1)递归就是在过程或函数里面调用自身; 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 递归分为两个阶段: 1)递推:把复杂的问题的求解推到比原问题简单一些的问题的求解; 2)回归:当获得最简单的情况后,逐步返回,依次得到复杂的解. 迭代 : 利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话,迭代就是A不停的调用B. 2.辩证看递归和迭代 所谓递归,简而言之就是应用程序自身调用自身,以实现层次数据结构的查询和访问。递归的使用可以使代码更简洁清晰,可读性更好(对于初学者到不见得),但由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多,而且,如果递归深度太大,可能系统资源会不够用。 往往有这样的观点:能不用递归就不用递归,递归都可以用迭代来代替。 诚然,在理论上,递归和迭代在时间复杂度方面是等价的(在不考虑函数调用开销和函数调用产生的堆栈开销),但实际上递归确实效率比迭代低,既然这样,递归没有任何优势,那么是不是就,没有使用递归的必要了

eetCode刷题-递归篇

二次信任 提交于 2019-12-03 01:36:05
递归是算法学习中很基本也很常用的一种方法,但是对于初学者来说比较难以理解(PS:难点在于不断调用自身,产生多个返回值,理不清其返回值的具体顺序,以及最终的返回值到底是哪一个?)。因此,本文将选择LeetCode中一些比较经典的习题,通过简单测试实例,具体讲解递归的实现原理。本文要讲的内容包括以下几点: 理解递归的运行原理 求解递归算法的时间复杂度和空间复杂度 如何把递归用到解题中(寻找递推关系,或者递推公式) 记忆化操作 尾递归 剪枝操作 理解递归的运行原理 例1求解斐波那契数列 题目描述(题目序号:509,困难等级:简单): 求解代码(基础版): class Solution { public int fib(int N) { if(N <= 1) return N; return fib(N - 1) + fib(N - 2); } } 现在以N = 5为例,分析上述代码的运行原理,具体如下图: 递归的返回值很多,初学者很难理解最终的返回值是哪个,此时可以采用上图的方式画一个树形图,手动执行递归代码,树形图的叶节点即为递归的终止条件,树形图的根节点即为最终的返回值。树形图的所有节点个数即为递归程序得到最终返回值的总体运行次数,可以借此计算时间复杂度,这个问题会在后文讲解。 例2 二叉树的三种遍历方式 二叉树的遍历方式一般有四种:前序遍历、中序遍历、后序遍历和层次遍历

递归算法和经典递归例子

匿名 (未验证) 提交于 2019-12-03 00:37:01
一、 什么叫递归 也就是自身调用自己。 二、 一般什么时候使用递归? 还有些 如二叉树, 结构本身固有递归特性 ;此外,有一类问题,其 本身没有明显的递归结构,但用递归程序求解比其他方法更容易 编写程序。 三、 经典递归算法 递归阶乘 n! = n * (n-1) * (n-2) * ...* 1(n>0) public static Integer recursionMulity(Integer n){ if(n==1){ return 1; } return n*recursionMulity(n-1); } 2、 汉诺塔问题 public static void hanio(int n,char a,char b,char c){ 8 if(n==1) 9 System.out.println("移动"+n+"号盘子从"+a+"到"+c); 10 else{ 11 hanio(n-1,a,c,b);//把上面n-1个盘子从a借助b搬到c 12 System.out.println("移动"+n+"号盘子从"+a+"到"+c);//紧接着直接把n搬动c 13 hanio(n-1,b,a,c);//再把b上的n-1个盘子借助a搬到c 14 } 15 } 3.判定一系列字符串中是否有相同的内容 public class Crf{ public static void main

函数递归总结

匿名 (未验证) 提交于 2019-12-03 00:33:02
1 函数递归的定义:函数自己直接或者间接的调用自己的函数,直到满足一个条件结束自己调用自己的函数的过程。每次调用函数都会开辟新的空间,递归调用可以看做是函数的嵌套调用。 2 递归算法的设计基本思想:对于一个复杂的问题:把原问题分解成相对简单的若干子问题,继续下去,直到子问题简单到能够直接求解。也就是到了递归的结束条件,也叫递归出口。 3 关键处:递归出口,逐步向出口逼近。 4 递归缺点:运行效率低。不建议使用。 5 递归的实例: (1)斐波那契数列(黄金分割数列) 例如:1,1,2,3,5,8,13..........在数学上,斐波那契数列被递归这样定义:F(0)=0;F(1)=1;F(n)=F(n-1)+F(n-2),(n>=2); 现在用递归求第100个数。 代码如下: static int count(int n){ if(n==1||n==2) { return 1; } return count(n-1)+count(n-2); } public static void main(String args[]) { int sum=count(100); System.out.println(sum); } (2)求解阶乘。例如求解100的阶乘 代码如下: public class Digui { public static int digui(int n){ if(n=

day16 -- 递归函数,二分查找

匿名 (未验证) 提交于 2019-12-03 00:32:02
一,递归函数 1,1初始递归 递归的最大深度 : 998 递归函数如果不受外力的阻止会一直执行下去,但是函数的每次调用都会产生一个属于自己的名称空间,如果一直调用下去的话,会出现名称空间过多导致的内存问题,所以为了避免这种现象,强制将递归层数控制在了997 def foo(n): print (n) n = n + 1 foo(n) foo( 1 1,2 ,递归示例 问alex多大了,告诉你alex比egon大两岁, 然后去问egon多大了,egon说我比wusir大两岁, 然后又去问wusir,wusir说他比太白大两岁, 然后去问太白,太白说他18,这样就可以计算出alex到底多大了 age(4) = age(3) + 2 age( 3) = age(2) + 2 age( 2) = age(1) + 2 age( 1) = 18 然后我们用函数表示 def age(n): if n == 1 : return 18 else : return age(n - 1) + 2 print (age(4 )) # 24 解析: def age(4):   if n == 1:     return 26   else:     return age(3) + 2 def age(3):   if n == 1:     return 26   else:     return

递归、迭代求斐波那契数列

匿名 (未验证) 提交于 2019-12-03 00:29:01
今天给大家分享一下基本算,就是使用递归、迭代求斐波那契数列,同时给解释迭代算法求解波那契数列的算法的时间复杂性和空间复杂性和分析递归算法求解波那契数列的算法的时间复杂性和空间复杂性。 对于迭代,确定迭代变量。在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。建立迭代关系式。所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式或关系。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。而且要对迭代过程进行控制。在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。下面就是迭代算法: #include<stdio.h> #define N 80 long fun( int);//函数调用 int main()//主函数 { int n;//定义 scanf("%d",&n);//输入 printf("the value is %ld\n",fun(n)); return 1; } long fun(int n) { long i; long Fib[N]; //定一个数组 Fib[0]=0;Fib[1]=1; //迭代算法控制 for(i=2;i<=n;i++) Fib[i]=Fib[i-1] + Fib[i-2]; return Fib[n]; } 结果:

【基础】递归和尾递归,我的个人看法

匿名 (未验证) 提交于 2019-12-03 00:22:01
之前只知道递归这个概念,无非是函数内部调用自己。 递归递归,有来有回。从调用的最外层开始一层一层往里进去直到最里层然后带着结果一层层出来到最外面返回。 那么 尾递归是什么呢? 很多篇文章拿阶乘来举例子。 我按照我的理解总结为 最后的返回值只有函数自身的调用,而不含有表达式。 函数递归调用过程中产生的中间累计的值以变量的形式存储在下一层函数的入参中,逐级传递下去 。 第二句话是我独创的。 接下来我们用代码来看看递归和尾递归的区别 # 递归 def func (n) : if n == 1 : return 1 else : return n * func(n - 1 ) 我们来看看这样的函数的计算过程 => func(5) => 5 * fact(4) => 5 * (4 * fact(3)) => 5 * (4 * (3 * fact(2))) => 5 * (4 * (3 * (2 * fact(1)))) => 5 * (4 * (3 * (2 * 1))) => 5 * (4 * (3 * 2)) => 5 * (4 * 6) => 5 * 24 => 120 我们再看看尾递归的代码和流程 def func (n, src) : if n == 1 : return src return func(n - 1 , n * src) => func(5, 1) => func

C++多线程的基本使用

匿名 (未验证) 提交于 2019-12-03 00:21:02
C++11增加了线程及线程相关的累,很方便的支持了并发编程,使得编写的多线程程序的可移植性得到了很大的提高. 线程的创建 用std::thread 创建线程非常的简单,只需要提供线程函数或者函数对象即可,并可以同时指定线程的参数: #include<iostream> #include<thread> #include<chrono> using namespace std ; //线程函数 void func( int a, int b, int c) { std ::this_thread::sleep_for( std ::chrono::seconds( 3 )); cout << a << " " << b << " " << c << endl; } int main() { //创建线程对象t1,绑定线程函数为func std ::thread t1(func, 1 , 2 , 3 ); //输出t1的线程ID std :: cout << "ID:" << t1.get_id() << std ::endl; //等待t1线程函数执行结束 t1.join(); std ::thread t2(func, 2 , 3 , 4 ); //后台执行t2的线程函数,并且不会因为main函数结束时,线程函数未执行完而产生异常 t2.detach(); cout <<