函数之递归[通俗易懂]

递归前戏在讲今天的内容之前,我们先来讲一个故事,讲的什么呢?从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么呢?从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么呢?从前有座山,山里有座

大家好,又见面了,我是你们的朋友全栈君。

递归

前戏

在讲今天的内容之前,我们先来讲一个故事,讲的什么呢?从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么呢?从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么呢?从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么呢?从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么呢……这个故事你们不喊停我能讲一天!我们说,生活中的例子也能被写成程序,刚刚这个故事,让你们写,你们怎么写呀?

while True:
    story = "
    从前有个山,山里有座庙,庙里老和尚讲故事,
    讲的什么呢?   
    "
    print(story)

你肯定是要这么写的,但是,现在我们已经学了函数了,什么东西都要放到函数里去调用、执行。于是你肯定会说,我就这么写:

def story():
    s = """
    从前有个山,山里有座庙,庙里老和尚讲故事,
    讲的什么呢?
    """
    print(s)
    
while True:
    story()

但是大家来看看,我是怎么写的!

def story():
    s = """
    从前有个山,山里有座庙,庙里老和尚讲故事,
    讲的什么呢?
    """
    print(s)
    story()
    
story()

先不管函数最后的报错,除了报错之外,我们能看的出来,这一段代码和上面的代码执行效果是一样的。

递归的概念:

在一个函数内部调用这个函数自身我们就可以将其称为递归函数

递归其实是倆个不同的过程:

递:是整个函数执行的过程是从上到下的顺序

归:是将执行的结果返回来是从下到上的顺序

def  story():
    info = '''
    从前有个山,山里有座庙,庙里老和尚讲故事,
    讲的什么呢?   
    '''
    print(info)
    story()

story()    

上面一个简单的示例诠释了递归函数概念:在story这个函数中调用了story函数自身那么我们就可以称story这个函数为递归函数。

我们现在知道了什么是递归函数,但是在执行这个函数的时候会发现执行以后会报错:RecursionError: maximum recursion depth exceeded while calling a Python object

这是为什么呢?是不是我们的递归函数写错了呢?不然为什么会报错呢?这就涉及到了一个新的知识点—递归函数的最大深度

递归的最大深度深度

什么是递归函数的最大深度呢?

  我们执行递归函数如果不受到外力的阻止会一直执行下去。但是我们之前已经说过关于函数调用的问题,每一次函数调用都会产生一个属于它自己的名称空间,如果一直调用下去,就会造成名称空间占用太多内存的问题,于是python为了杜绝此类现象,强制的将递归层数控制在了997

  怎么证明递归的最大深度是997呢?

函数之递归[通俗易懂]
函数之递归[通俗易懂]

def foo(n):
    print(n)
    n += 1
    foo(n)
foo(1)

测试递归最大深度

通过执行上述代码知道在程序没有报错之前执行的 最大值就是997,当然997是python为了我们程序的内存优化所设定的一个默认值,我们当然还可以通过一些手段去修改它:

函数之递归[通俗易懂]
函数之递归[通俗易懂]

import sys
print(sys.setrecursionlimit(100000))

修改递归最大深度值

我们可以通过这种方式来修改递归的最大深度,刚刚我们将python允许的递归深度设置为了10w,至于实际可以达到的深度就取决于计算机的性能了。不过我们还是不推荐修改这个默认的递归深度,因为如果用997层递归都没有解决的问题要么是不适合使用递归来解决要么是你代码写的太烂了~~~

看到这里,你可能会觉得递归也并不是多么好的东西,不如while True好用呢!然而,江湖上流传这这样一句话叫做:人理解循环,神理解递归。所以你可别小看了递归函数,很多人被拦在大神的门槛外这么多年,就是因为没能领悟递归的真谛。而且之后我们学习的很多算法都会和递归有关系。来吧,只有学会了才有资本嫌弃!

递归的深入了解

通过对初始递归这个小结的了解  我们对递归也有了一定的了解 当然了只是初步的了解 ,那么就让我们再来深入的了解一下吧 毕竟这样才可以掌握的更扎实嘛

函数之递归[通俗易懂]
函数之递归[通俗易懂]

现在你们问我,alex老师多大了?我说我不告诉你,但alex比 egon 大两岁。
你想知道alex多大,你是不是还得去问egon?egon说,我也不告诉你,但我比武sir大两岁。
你又问武sir,武sir也不告诉你,他说他比金鑫大两岁。
那你问金鑫,金鑫告诉你,他40了。。。
这个时候你是不是就知道了?alex多大?
1  金鑫   40
2  武sir    42
3  egon  44
4  alex  46
你为什么能知道的?
首先,你是不是问alex的年龄,结果又找到egon、武sir、金鑫,你挨个儿问过去,一直到拿到一个确切的答案,然后顺着这条线再找回来,才得到最终alex的年龄。这个过程已经非常接近递归的思想。我们就来具体的我分析一下,这几个人之间的规律。
age(4) = age(3) + 2 
age(3) = age(2) + 2
age(2) = age(1) + 2
age(1) = 40
那这样的情况下,我们的函数应该怎么写呢?

def age(n):
    if n == 1:
        return 40
    else:
        return age(n-1)+2

print('alex的年龄是:%s'%age(4))

猜年龄深入了解递归

怎么样通过上面的例子相信你一定对递归有了一个更深刻的理解了吧  那么就请牢牢的记住吧  它的用处非常的大哦,不相信你会后悔的!!!

递归和三级菜单

函数之递归[通俗易懂]
函数之递归[通俗易懂]

数据结构:

menu = {
    '北京':{
        '海淀':{
            '五道口':{
                'soho':{},
                '网易':{},
                'google':{}
            },
            '中关村':{
                '爱奇艺':{},
                '汽车之家':{},
                'youku':{},
            },
            '上地':{
                '百度':{},
            },
        },
        '昌平':{
            '沙河':{
                '老男孩':{},
                '北航':{},
            },
            '天通苑':{},
            '回龙观':{},
        },
        '朝阳':{},
        '东城':{},
    },
    '上海':{
        '闵行':{
            "人民广场":{
                '炸鸡店':{}
            }
        },
        '闸北':{
            '火车战':{
                '携程':{}
            }
        },
        '浦东':{},
    },
    '山东':{},
}


需求:
可依次选择进入各子菜单
可从任意一层往回退到上一层
可从任意一层退出程序

#递归方式实现
def show_Menu(ch):
    for s in ch:
        print(s)
    print('返回/退出')
    p = input('您选择是')
    if p == '退出':
        exit()
    elif p == '返回' and ch != menu:
        return
    else:
        if p in ch:
            show_Menu(ch[p])
        show_Menu(ch)
show_Menu(menu)

递归实现三级菜单

递归和二分算法

递归我们已经知道是怎么回事,那么算法又是怎么回事呢?很简单啊,你通过字面就可以解释啊:就是计算的方法嘛。那么下面我们就通过示例来看一下什么是二分算法吧

如果有一个列表,让你从这个列表中找到66的位置,你要怎么做?

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

l.index(66) 这不就解决问题了吗

这确实可以解决问题,是因为我们用的index方法内部提供了__next__()方法就相当于for循环遍历了整个列表,我们的示例数据量比较小这样做可以但是如果有一个非常大的数据达了几万或者几十万的话这样做会占用很大的内存导致程序运行缓慢甚至崩溃 这该怎么办呢 这就用到了我们要学习的二分法

二分法概念

其实就是一种通过不断的排除不可能的东西,来最终找到需要的东西的一种方法.所以可以理解成排除法.之所以叫二分,是因为每次排除都把所有的情况分成"可能""不可能"两种,
然后抛弃所有"不可能"的情况.最正统的二分法中,是每次排除都可以排除掉一半的情况,这样子的寻找效率是很高的.
 ps:二分查找算法 必须处理有序的列表
函数之递归[通俗易懂]
函数之递归[通俗易懂]

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

def find(l,aim):
    mid_index = len(l) // 2
    if l[mid_index] < aim:
        new_l = l[mid_index+1 :]
        find(new_l,aim)
    elif l[mid_index] > aim:
        new_l = l[:mid_index]
        find(new_l, aim)
    else:
        print('找到了',mid_index,l[mid_index])

find(l,66)

二分法实现数据查找

ps:使用二分法查找数据数据必须是有序的列表方可

函数之递归[通俗易懂]
函数之递归[通俗易懂]

l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

def find(l,aim,start = 0,end = None):
    end = len(l) if end is None else end
    mid_index = (end - start)//2 + start
    if start <= end:
        if l[mid_index] < aim:
            return find(l,aim,start =mid_index+1,end=end)
        elif l[mid_index] > aim:
            return find(l, aim, start=start, end=mid_index-1)
        else:
            return mid_index
    else:
        return '找不到这个值'

进阶(终极版本)

 

 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/124536.html原文链接:https://javaforall.net

(0)
上一篇 2022年3月29日 下午12:35
下一篇 2022年3月29日 下午1:00


相关推荐

  • 小米4usb调试模式怎么打开_安卓打开USB调试模式

    小米4usb调试模式怎么打开_安卓打开USB调试模式我们要将小米4与电脑进行连接,就必须要打开小米4系统的调试模式,不同的系统版本打开调试模式的方法有所不同,在这里我们就谈谈小米4各种系统版本打开USB调试模式的方法。1、针对Android2.1-2.2版本的系统:我们在桌面按小米4手机上的“菜单键”会弹出菜单,点击“设置”选项进入系统的设置菜单列表,然后进入“应用程序”—“开发”,就可以看到“USB调试”选项,我们勾选即可。2、针…

    2025年11月8日
    3
  • 【深度学习入门】——亲手实现图像卷积操作[通俗易懂]

    【深度学习入门】——亲手实现图像卷积操作[通俗易懂]深度学习中有一个很重要的概念就是卷积神经网络CNN,卷积神经网络中又有卷积层、池化层的概念。尤其是卷积层,理解难度比较大,虽然书中或者是视频中都有详细介绍过它的基础概念,但对于求知欲望很强烈的我,我总心里痒痒的,总想亲手实现,看看效果,怕的就是自己会眼高手低,做技术人最可怕的就是眼高手低。所以,我打算用python来亲自验证一遍。什么是卷积?卷积(convolution)是数学知…

    2022年5月8日
    76
  • pycharm安装与注册

    pycharm安装与注册安装选择好自己的安装路径后 点击 NEXT 这里把所有勾给打上 后面一直点击 next 直到安装完成 注册双击运行刚才安装的软件后面就点击 next 和 accept 就好了先点击第一步在点击第二步然后点击 continue 进行到下一步 下一步把安装包拖进来点击 restart 在点击为 pycharm 安装 点击是就好创建一个项目后可以进入菜单查看使用时间可以看到使用时间到 2089 年了 就安装注册好了

    2026年3月27日
    1
  • connectionstrings汇总

    connectionstrings汇总http://www.connectionstrings.com/所有的数据库连接语句

    2022年5月22日
    27
  • 快递单号查询API接口-光线速递

    快递单号查询API接口-光线速递前言看完快递鸟 api 光线速递对接教程这篇文章 把源码复制到项目上 就能快速完成接口对接 适合刚入门的菜鸟 调用快递鸟的光线速递查询 API 接口 能查询到光线速递单号从收件 运输 到转运中心 派送到签收等各个环节的物流发货状态 快递鸟 api 接口不区分开发语言 支持 Java C PHP Python ObjectC 等开发语言的程序调用 下面具体讲解实现过程 目录 1 完成前期准备工作 2

    2026年3月26日
    3
  • jmeter安装教程

    jmeter安装教程基于windows,jmeter4.0版本。1.下载安装包地址:http://jmeter.apache.org/download_jmeter.cgi2.解压,配置环境2.1新增系统变量JMETER_HOME变量值:E:\developer\apache-jmeter-4.0注意,根据自己的路径配置,到这一级就好了。2.2配置classpath在…

    2022年5月3日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号