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

1. 介绍

一说起递归,我想每个人都不陌生。举个从小就听过的例子:从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山...

还有你从两面相对的镜子中看到的画面,其实都是抽象出来的递归现象,但是严格来说并不是递归,因为会一直重复下去,没有终止条件,那就称为死循环了。有关递归和死循环的异同我们之后会说到,那么现在先来了解一下什么是递归?

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

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

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

2. 示例

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

5b6fac208b0ad.jpg

function Recursion(depth) {    
    console.log('抱着');    
    if (!depth) {        
        console.log('我的小鲤鱼')
    } else {
        Recursion(--depth);  // 递归调用
    }    
        console.log('的我');
}
        
console.log('吓得我抱起了');
Recursion(2)

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

image.png

代码其实十分简单,但是需要理解的是:if代码块的条件(!depth)为递归调用的终止条件,在else代码块内递归调用函。

我们前面有说到递归的过程是存在前行和退回阶段的,那么在前行阶段我们在每次调用函数后,打印出了"抱着",并且当 depth≠0 时重新调用该函数;在退回阶段,将会去执行代码 console.log('的我');再打印出"的我"。

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

5b6fac206abe6.jpg


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

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 osdef 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路径下的所有文件:

5b6fac208b78a.png

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

import osdef 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. 循环与递归总结

好了,递归的知识差不多介绍完了。如果看完上边大概已经了解了循环和递归的区别了。

简单来说,循环是执行一段代码,一直向前走;而递归则是有去有回(因为存在终止条件)。

举个栗子:

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

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


作者:pushy


原文链接:HelloWeb前端网 » 什么是递归?先了解什么是递归. » 感谢您的浏览,希望能有所帮助。

欢迎您加入“Helloweb” 学习交流群:HelloWeb-学习交流群 196291215 共同交流并结识同行,在这里说出您的收获与感想或有什么不同的观点,我们期待您的留言,分享,让我们一起进步!

喜欢 ()or分享