函数之递归[通俗易懂]

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

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

递归

前戏

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

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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • springboot整合jedisCluster[通俗易懂]

    springboot整合jedisCluster[通俗易懂]JedisClusterjedis客户端提供的一个操作集群的连接对象;底层封装了单个节点电连接对象,封装了连接池的对外使用的集群对象;测试连接代码•收集节点信息(redis-cluster可以只提供若干个节点) @Test publicvoidtest(){ //收集若干个节点信息 Set<HostAndPort>set=newHashSet<Ho…

    2022年10月14日
    0
  • HTML5_ScrollInToView方法「建议收藏」

    HTML5_ScrollInToView方法「建议收藏」HTML5_ScrollInToView方法 window.onload=function(){ /* 如果滚动页面也是DOM没有解决的一个问题。为了解决这个问题,浏览器实现了一下方法, 以方便开发人员如何更好的控制页面的滚动。在各种专有方法中,HTML5选择了scrollIntoView() 作为标准方法。 scrollIntoV

    2022年6月24日
    27
  • 【Web攻防】红队外围信息收集【总结】

    【Web攻防】红队外围信息收集【总结】​外围打点前言由于红队不同于一般的渗透测试,强调更多的是如何搞进去拿到相应机器权限或者实现某特定目的,而不局限于你一定要在什么时间,用什么技术或者必须通过什么途径去搞,相比传统渗透测试,红队则更趋于真实的入侵活动,这种场景其实对防御者的实战对抗经验和技术深度都是比较大的挑战信息收集方式一般采取以下几种方式在搜索引擎(如:baidu、google)进行搜索: 主站相关联的链接,主站链接下可能会放置跳转,如邮件、OA等相关系统。 主站子域名进行搜索,通过二级或三级域名进行目标搜索相.

    2022年6月22日
    24
  • java aqs详解_Java中的File文件类详解

    java aqs详解_Java中的File文件类详解今天学了学并发AQS机制,是抽象队列同步器,用户主要通过继承AQS类,来实现自定义锁,从而完成特定功能,AQS提供了两种锁(1)共享锁(2)排他锁。下面这个博客介绍的AQS机制挺不错可以看看原文链接一、概述  谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock

    2022年8月8日
    8
  • Python 之 cPickle用法

    Python 之 cPickle用法序列化就是通过特殊的方法将数据存储到相应存储区的过程,反序列化就是依据数据序列化时的规则进行反向执行,以取出原数据的过程。在编写程序的过程中,我们有时需要将数据进行序列化与反序列化的操作,本篇博客旨在阐述序列化与反序列化的作用及举例说明几个常用方法的使用。

    2022年6月24日
    26
  • Java数据结构与算法(排序)——基数排序(LSD)

    Java数据结构与算法(排序)——基数排序(LSD)一、基本思想先从最低位开始排序,再对次低位排序,直到对最高位排序后得到一个有序序列(位数不同时高位补0)。二、举例分析假设有一串数列:73,22,93,43,55,14,28,65,39,81。排序过程如下:(1)先根据个位进行排序,得到:0——1——812——223——73,93,434——145——55,656——7——8——289——39(2…

    2022年5月6日
    45

发表回复

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

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