什么是递归?先了解什么是递归.

你好!欢迎阅读我的博文,你可以跳转到我的个人博客网站,会有更好的排版效果和功能。

此外,本篇博文为本人Pushy原创,如需转载请注明出处:http://blog.pushy.site/posts/1519134018

一说起递归,我想每个人都不陌生.举个从小就听过的例子:从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山...,还有你从两面相对的镜子中看到的画面,其实都是抽象出来的递归现象,但是严格来说并不是递归,因为会一直重复下去,没有终止条件,那就称为死循环了.有关递归和死循环的异同我们之后会说到,那么现在先来了解一下什么是递归?

那么什么是递归呢? 要理解递归,就得先了解什么是递归,实际上这句话就是一个递归.这么说可能不好理解,接下来我举个简单的例子来解释这段话的意义.

假设我们现在都不知道什么是递归,我们自然想到打开浏览器,输入到谷歌的网页,我们点击搜索递归,然后我们在为维基百科中了解到了递归的基本定义,在了解到了递归实际上是和栈有关的时候,你又蒙圈了,什么是栈呢?数据结构没学清楚,此时的你只能又打开谷歌,搜索什么是栈.接下来你依次了解了内存/操作系统.在你基本了解好知识之后,你通过操作系统了解了内存,通过内存了解了栈,通过栈了解了什么是递归这下你恍然大悟!原来这就是递归啊!

这下应该有点明白了吧,这个过程其实就是递归的过程,如果不了解递归,那就先了解什么是递归,可能你会说这是个循环并不是递归,我们前面说到,递归是需要终止条件的,那么你明白递归是什么其实就是终止条件.整个过程,搜索引擎充当递归函数(只是形象的假设);在你去依次查找递归/栈/内存/操作系统的过程为前行阶段,在你都了解完之后,反回去了解含义的过程为退回阶段.如果还是不太清楚,可以接着看下面的例子

2. 示例:

也许之前你在网络上看到过这张图片:

实际上这张图就很形象地表达出了递归,这句吓得我抱起了抱着抱着抱着我的小鲤鱼的我的我的我如果从字面意义上看可能看不出是什么意思,那么我们可以通过代码来实现同样的效果:

function Recursion(depth) {
    console.log(‘抱着‘);
    if (!depth) {
        console.log(‘我的小鲤鱼‘)
    } else {
        Recursion(--depth);  // 递归调用
    }
    console.log(‘的我‘);
}

console.log(‘吓得我抱起了‘);
Recursion(2)

在终端的打印结果为如下,可以看到和上面的那段话是一样的:

代码其实十分简单,但是需要理解的是:if代码块的条件(!depth)为递归调用的终止条件,在else代码块内递归调用函数.我们前面有说到递归的过程是存在前行和退回阶段的,那么在前行阶段我们在每次调用函数后,打印出了"抱着",并且当depth≠0时重新调用该函数;在退回阶段,将会去执行代码console.log(‘的我‘);再打印出"的我".

褚跃跃的图也能比较清楚地反映出这个过程:

好了!这下你应该明白什么是递归了吧?如果你还没有明白什么是递归的话,你可以看这里

3. 应用:

3.1 斐波拉契数列:

有关递归应用的应用有很多,例如注明的斐波拉契数列就可以通过递归来实现:

def fib(x):
    if x < 2:
        return 0 if x == 0 else 1
    # 当x > 2时,开始递归调用fib()函数:
    return fib(x - 1) + fib(x - 2)

print(fib(6))  # 打印结果为:8

这里需要对i<2时的特殊情况做出判断,当x==0时,直接返回0,当x==1时,直接返回1

3.2 遍历文件:

首先我们需要了解遍历的算法:定义的file_display函数以某个目录(/home/pushy)作为遍历的起点.遇到一个子目录时,就先接着遍历子目录(递归调用函数);遇到一个文件时,就直接对改文件进行操作(这里只打印出文件的文件名):

import os

def file_display(filepath):
    for each in os.listdir(filepath):
        # 得到文件的绝对路径:
        absolute_path = os.path.join(filepath, each)
        # 得到是否为文件还是目录的布尔值:
        is_file = os.path.isfile(absolute_path)
        if is_file:
            # 当前的绝对路径为文件:
            print(each)
        else:
            # 当前的绝对路径为目录:
            file_display(absolute_path)

file_display(‘/home/pushy‘)

这样我们就可以遍历到/home/pushy路径下的所有文件:

另外我们还可以使用递归来创建目录:

import os

def createFile(dirname):
    exits = os.path.exists(dirname)
    if exits:
        return True
    else:
        # 开始递归调用函数,并接受其返回值:
        rec_result = createFile(os.path.dirname(dirname))
        if rec_result:
            # 如果不存在该目录,则创建dirname的目录,并返回已经创建(存在)的值True:
            os.mkdir(dirname)
            return True

createFile(‘./aa/bb/cc‘)

4. 循环与递归:

好了,递归的知识差不多介绍完了.如果看完上边大概已经了解了循环和递归的区别了.对了!简单来说,循环是有去无回,而递归则是有去有回(因为存在终止条件).

举个栗子,你用你手中的钥匙打开一扇门,结果去发现前方还有一扇门,紧接着你又用钥匙打开了这扇门,然后你又看到一扇们...但是当你开到某扇门时,发现前方是一堵墙无路可走了,你选择原路返回.这就是递归

但是如果你打开一扇门后,同样发现前方也有一扇们,紧接着你又打开下一扇门...但是却一直没有碰到尽头,这就是循环.

参考资料:

[知乎]什么是递归

七天学会NodeJs--递归算法

原文地址:https://www.cnblogs.com/Pushy/p/8455862.html

时间: 2024-10-24 10:51:55

什么是递归?先了解什么是递归.的相关文章

Why coding like This ------ 递归以及枚举中的递归

title: "Why coding like This -- 递归以及枚举中的递归" date: 2015-08-28 21:34:16 categories: "why coding like this" tags: [swift进阶] Topic 1: 输入一个数组xs:[Int],对全体元素求和. Discuss 思路一: Hey,伙计,遍历数组,逐个相加,so easy! code: func sum1(xs:[Int])->Int{ var sum

递归如何转换成非递归

为什么要讲递归呢? 因为递归很复杂,需要很长时间,见识过很多例子,包括了解好多数据结构才能深刻体会到如何使用递归,有时候,我们也不知道是否可以使用还是不能使用递归,其实可以通过非递归思想去理解,然后通过递归算法来进行编程实现,都是一个很好的方向,递归的本质是栈. 递归一般使用栈和队列使用区别? 通过很多例子发现凡是使用深度优先都是使用递归算法,凡是使用层次遍历的使用的都是队列.这个让我们怎么理解,我个人发现一个小的情况就是,递归它一般都是有一定的关系的,如深度优先遍历,它都是一个结点和另外一个结

数据结构与算法 —— 递归的效率问题以及递归与循环的比较

1.所谓的递归慢到底是什么原因呢? 大家都知道递归的实现是通过调用函数本身,函数调用的时候,每次调用时要做地址保存,参数传递等,这是通过一个递归工作栈实现的.具体是每次调用函数本身要保存的内容包括:局部变量.形参.调用函数地址.返回值.那么,如果递归调用N次,就要分配N*局部变量.N*形参.N*调用函数地址.N*返回值.从而导致了效率的低下. 2.用循环效率会比递归效率高吗? 递归与循环是两种不同的解决问题的典型思路.当然也并不是说循环效率就一定比递归高,递归和循环是两码事,递归带有栈操作,循环

递归学习总结及使用递归实现n!(另附上n!数组实现)

一,递归的概念及其作用程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量.递归的能力在于用有限的语句来定义对象的无限集合.一般来说,递归需要有边界条件.递归前进段和递归返回段.当边界条件不满足时,递归前进:当边界条件满足时,递

MIT Python 第四课函数抽象与递归简介 最后三分钟递归的经典案例:斐波那契数列

斐波那契数列Fibonacci Sequence,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*) 有一对一个月大的一公一母的兔子,再过一个月的时候交配生小兔子,假设它们生的是两只一公一母的小兔子,在下一个月末这两只小兔子也有了后代同样是一公一母,问题是一年后你会有多少只小兔子?[呲牙]第三年的时候就像到了澳大利亚... >>&g

Java 递归、尾递归、非递归 处理阶乘问题

n!=n*(n-1)! import java.io.BufferedReader; import java.io.InputStreamReader; /** * n的阶乘,即n! (n*(n-1)*(n-2)*...1). * 0!为什么=1,由于1!=1*0!.所以0!=1 * * @author stone * @date 2015-1-6 下午18:48:00 */ public class FactorialRecursion { static long fact(long n) {

深度优先搜索入门:POJ1164城堡问题(递归、用栈模拟递归)

将问题的各状态之间的转移关系描述为一个图,则深度优先搜索遍历整个图的框架为:Dfs(v) {if( v 访问过)return;将v标记为访问过;对和v相邻的每个点u: Dfs(u);}int main() {while(在图中能找到未访问过的点 k) Dfs(k);} 例题: POJ1164 The Castle Description 1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---#####---#-

网易云课堂_C语言程序设计进阶_第五周:递归与简单算法:递归、搜索、二分搜索、简单排序_1逆序输出的数列

1 逆序输出的数列(10分) 题目内容: 你的程序会读入一系列的正整数,预先不知道正整数的数量,一旦读到-1,就表示输入结束.然后,按照和输入相反的顺序输出所读到的数字,不包括最后标识结束的-1. 输入格式: 一系列正整数,输入-1表示结束,-1不是输入的数据的一部分. 输出格式: 按照与输入相反的顺序输出所有的整数,每个整数后面跟一个空格以与后面的整数区分,最后的整数后面也有空格. 输入样例: 1 2 3 4 -1 输出样例: 4 3 2 1 时间限制:2000ms内存限制:128000kb

Java 递归、尾递归、非递归、栈 处理 三角数问题

import java.io.BufferedReader; import java.io.InputStreamReader; //1,3,6,10,15...n 三角数 /* * # 1 * ## 1+2 * ### 1+2+3 * #### 1+2+3+4 * ##### 1+2+3+4+5 * ...第1层为1, 第n层等于 n + (f(n-1)) */ public class TriangleNumber { static int triangle(int n) { if (n <