递归调用

python递归详解+汉诺塔小案例

旧街凉风 提交于 2020-01-25 18:09:17
递归 什么是 递归 ? 递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。绝大多数编程语言支持函数的自调用,在这些语言中函数可以通过调用自身来进行递归。计算理论可以证明递归的作用可以完全取代循环,因此在很多函数编程语言(如Scheme)中习惯用递归来实现循环。递归的强大之处在于它允许用户用有限的语句描述无限的对象。因此,在计算机科学中,递归可以被用来描述无限步的运算,尽管描述运算的程序是有限的。下面是对Python递归函数的简单了解: # 类似与栈的先进后出模式 # 递归的两个必要条件 # 1.要有递推关系 # 2.要有临界 def digui(num): print('$'+str(num)) # 临界值 if num >0: # 这里用的是调用本身的函数(递推关系) digui(num-1) else: print('='*20) print(num) digui(3) 输出结果为: $3 $2 $1 $0 ==================== 0 1 2 3 汉诺塔 什么是 汉诺塔 ? 汉诺塔算法介绍 其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n – 1(有兴趣的可以自己证明试试看)。后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了。首先把三根柱子按顺序排成品字型

递归1--小游戏

不羁岁月 提交于 2020-01-25 08:51:29
递归1--小游戏 零:本题总结 1、回溯迷宫问题 2、扩充边界 一、递归基本思想 定义:函数直接或者间接调用自身 应用场景:原问题复杂,但是可以划分成许多性质相同的子问题,子问题容易求解 递归写法:1、先写出问题的递推公式 2、递归部分的边界条件就是递推公式中的边界条件 3、递归部分的主体部分就是递推公式中的主体部分 递归在内存中的实现方式:系统通过栈来实现(通过栈去讲) 递归简单实例:http://www.cnblogs.com/Renyi-Fan/p/6914840.html 二、递归实例题目 题目: 有一个w * h 个正方格子的矩形板,每个正方格子上可以有一张游戏卡片, 当然也可以没有,当下面的情况满足时,认为 两个游戏卡片之间有一条路径相连:1、路径只包含水平或者竖直的直线段;2、路径不能穿过别的游戏卡片;3、但是允许 路径临时的离开矩形板。判断是否存在一条满足题意的路径能连接给定的两个游戏卡片。 输入: 输入包括多组数据: 一个矩形板对应一组数据 第一行包括两个整数 w和h (1 <= w, h <= 75),分别表示矩形板的宽度和长度 下面的h行, 每行包括w个字符, 表示矩形板上的游戏卡片分布情况: 使用 ‘X’ 表示这个地方有一个游戏卡片,使用空格 表示这个地方没有游戏卡片 之后每行上包括4个整数: x1, y1, x2, y2 (1 <= x1, x2 <= w

js函数实现递归自调用的方法

夙愿已清 提交于 2020-01-25 05:43:35
js函数的递归调用方法 1.通过函数自身名字递归调用 function sum(num){ if(num<=1){ return 1; }else{ return num+sum(num-1); } } console.log(sum(5));//15 这种通过函数名字调用自身的方式存在一个问题:函数的名字是一个指向函数对象的指针,如果我们把函数的名字与函数对象本身的指向关系断开,这种方式运行时将出现错误。 2.通过arguments.callee调用函数自身 function sum(num){ if(num<=1){ return 1; }else{ return num+arguments.callee(num-1); } } console.log(sum(5));//15 var sumAnother=sum; console.log(sumAnother(5));//15 sum=null; console.log(sumAnother(5));//15 这种方式很好的解决了函数名指向变更时导致递归调用时找不到自身的问题。但是这种方式也不是很完美,因为在严格模式下是禁止使用arguments.callee的。 3.通过函数命名表达式来实现arguments.callee的效果。 var sum=(function(){ 'use strict' return

Java动态规划

别说谁变了你拦得住时间么 提交于 2020-01-25 05:31:18
1. 介绍 动态规划典型的被用于优化递归算法,因为它们倾向于以指数的方式进行扩展。动态规划主要思想是将复杂问题(带有许多递归调用)分解为更小的子问题,然后将它们保存到内存中,这样我们就不必在每次使用它们时重新计算它们。 要理解动态规划的概念,我们需要熟悉一些主题: 什么是动态规划? 贪心算法 简化的背包问题 传统的背包问题 Levenshtein Distance LCS-最长的共同子序列 利用动态规划的其他问题 结论 本文所有代码均为 java 代码实现。 2. 什么是动态规划? 动态规划是一种编程原理,可以通过将非常复杂的问题划分为更小的子问题来解决。这个原则与递归很类似,但是与递归有一个关键点的不同,就是每个不同的子问题只能被解决一次。 为了理解动态规划,我们首先需要理解递归关系的问题。每个单独的复杂问题可以被划分为很小的子问题,这表示我们可以在这些问题之间构造一个递归关系。 让我们来看一个我们所熟悉的例子: 斐波拉契数列 ,斐波拉契数列的定义具有以下的递归关系: 注意:递归关系是递归地定义下一项是先前项的函数的序列的等式。 Fibonacci 序列就是一个很好的例子。 所以,如果我们想要找到斐波拉契数列序列中的第n个数,我们必须知道序列中第n个前面的两个数字。 但是,每次我们想要计算 Fibonacci 序列的不同元素时,我们在递归调用中都有一些重复调用,如下图所示

单向链表_找出倒数第K个节点

只谈情不闲聊 提交于 2020-01-24 22:15:07
实现一个算法,找出单向链表中倒数第K个结点。 解法: 实现这个算法,可以用递归和非递归。因为单向链表只能向后遍历,所以一般会想到用递归这种方法,然后当递归遍历到链表末端时,该方法会回传一个置为0的计数器。 之后的每一次调用都会将这个计数器加1,当计数器等于K时,表示我们访问的是链表倒数第K个元素。 方法A public static int nToLast(LinkedListNode head,int k){ if(head==null){ return 0; } int i = nToLast(head.next,k)+1;//当遍历到最后一个元素时,计数器i开始自增。</span> if(i==k){ System.out.println(head.data); } return i; } <span style="color:#33cc00;">//但是这个方法只能打印倒数第K个值,不能返回该元素,因为我们无法用一般的返回语句回传一个结点和一个计数器。</span> 方法B: 可以通过引用传值,这样一来,我们就可以返回结点值,而且也能通过传递指针更新计数器。 node* nToLast(node* head,int k,int& i){ if(head==null){ return null; } node* nd = nToLast(head.next,k,i); i=i

知识点二十:分治算法

我们两清 提交于 2020-01-24 17:47:34
前言 MapReduce 是 Google 大数据处理的三驾马车之一,另外两个是 GFS 和 Bigtable。MapReduce在倒排索引、PageRank 计算、网页分析等搜索引擎相关的技术中都有大量的应用。尽管开发一个 MapReduce 看起来很高深,感觉跟我们遥不可及。实际上,万变不离其宗,它的本质就是 分治算法 。 如何理解分治算法? 分治算法(divide and conquer)的核心思想其实就四个字: 分而治之 ,也就是 将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解 。这个定义看起来有点类似递归的定义。关于分治和递归的区别,我们只要记住一点, 分治算法是一种处理问题的思想,而递归是一种编程技巧 。实际上,分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作: 分解:将原问题分解成一系列子问题; 解决:递归地求解各个子问题,若子问题足够小,则直接求解; 合并:将子问题的结果合并成原问题。 分治算法能解决的问题,一般需要满足下面这几个条件: 原问题与分解成的小问题具有相同的模式; 原问题分解成的子问题可以独立求解, 子问题之间没有相关性 ,这一点是分治算法跟动态规划的明显区别; 具有分解终止条件,也就是说,当问题足够小时,可以直接求解;

249 递归:概念,利用递归求1~n的阶乘,利用递归求斐波那契数列,利用递归遍历数据

ぃ、小莉子 提交于 2020-01-24 11:51:18
6.1什么是递归 递归: 如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。 简单理解: 函数内部自己调用自己, 这个函数就是递归函数 注意: 递归函数的作用和循环效果一样,由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件return。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script> // 递归函数 : 函数内部自己调用自己, 这个函数就是递归函数 var num = 1; function fn() { console.log('我要打印6句话'); if (num == 6) { return; // 递归里面必须加退出条件 } num++; fn(); } fn(); </script> </body> </html> 6.2 利用递归求1~n的阶乘 <!DOCTYPE html> <html lang="en"

递归算法学习系列之八皇后问题

孤街醉人 提交于 2020-01-23 15:36:07
1.引子 中国有一句古话,叫做“不撞南墙不回头",生动的说明了一个人的固执,有点贬义,但是在软件编程中,这种思路确是一种解决问题最简单的算法,它通过一种类似于蛮干的思路,一步一步地往前走,每走一步都更靠近目标结果一些,直到遇到障碍物,我们才考虑往回走。然后再继续尝试向前。通过这样的波浪式前进方法,最终达到目的地。当然整个过程需要很多往返,这样的前进方式,效率比较低下。 2.适用范围 适用于那些不存在简明的数学模型以阐明问题的本质,或者存在数学模型,但是难于实现的问题。 3.应用场景 在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。国际象棋的棋盘如下图所示: 4.分析 基本思路如上面分析一致,我们采用逐步试探的方式,先从一个方向往前走,能进则进,不能进则退,尝试另外的路径。首先我们来分析一下国际象棋的规则,这些规则能够限制我们的前进,也就是我们前进途中的障碍物。一个皇后q(x,y)能被满足以下条件的皇后q(row,col)吃掉 1)x=row(在纵向不能有两个皇后) 2) y=col(横向) 3)col + row = y+x;(斜向正方向) 4) col - row = y-x;(斜向反方向) 遇到上述问题之一的时候,说明我们已经遇到了障碍,不能继续向前了。我们需要退回来,尝试其他路径。 我们将棋盘看作是一个8*8的数组

递归函数最终会结束,那么这个函数一定(不定项选择)

匆匆过客 提交于 2020-01-23 03:50:33
递归函数最终会结束,那么这个函数一定(不定项选择): 1. 使用了局部变量 2. 有一个分支不调用自身 3. 使用了全局变量或者使用了一个或多个参数 1显然不是,局部变量只在一次调用局部范围有效,出了这次调用的范围就无效了,它不能控制递归的结束。(这个选项是考查局部变量生命周期/有效范围的问题)需要注意的就是局部变量不是局部静态变量。 对于2,很自然了,如果没有一个分支不调用自身,递归就不会结束了。(这是在考查递归的定义: 编程语言中,函数Func(Type a,……)直接或间接调用函数本身,则该函数称为递归函数。递归函数不能定义为内联函数。必定存在可使递归调用终止的条件,否则导致出现无限递归。 ) 对于3,这是最有迷惑性的,因为使用全局变量或使用一个或多个参数的确可以控制递归的结束,但是不是只有这两种方式呢?所以题目中指出了"一定"。答案是并不是只有这两种方式。 来源: CSDN 作者: 康斯坦奇 链接: https://blog.csdn.net/qq_40245974/article/details/103821294

全排列算法的递归思想及实现

安稳与你 提交于 2020-01-23 01:19:37
题意: 给定1~n n个正整数,写出它们的所有排列顺序。 思路 :根据高中的知识,我们知道不重复的条件下结果是n!个排列顺序,在程序中我们先看看如何用递归来实现。 例如数组{1,2,3}的全排列为123,132,213,231.312.321。 可以看出一点规律来,我们依次交换了第一个数字,分别从1到3,后面是剩下数字的全排列,这里就能看出应该使用递归来实现了。 算法: 首先依次交换第一个数字和每一位数字,再递归调用,最后将交换后的数组复原,以进行下一次的交换。 我自己的疑惑: 在最开始看到这个题目和解法的时候,虽然能理解思路,但是看到代码还是不能完全弄懂,自己也尝试去模拟递归中的每一个步骤,但是发现其中太复杂了,最后还是看了好多人的博客对全排列的解释,才从根本思路上理解了代码的含义。 代码: void perm(int a[],int n, int m) { if(n == m) { for(int i=0;i<m;i++) cout<<a[i]<<" "; cout<<"\n"; } else { for(int j = n;j<m;j++) { swap(a[n], a[j]); perm(a,n+1,m); swap(a[j],a[n]); } } } 来源: https://www.cnblogs.com/puyangsky/p/4697146.html