zoukankan      html  css  js  c++  java
  • 递归函数与算法

    一、递归函数

    1.1、定义

      在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

    1.2、递归函数特性

    1. 必须有一个明确的结束条件;
    2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
    3. 相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)。
    4. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

     2.1、递归的最大深度——997

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

    示例如下:

     1 # 997理论
     2 def foo(n):
     3     print(n)
     4     n += 1
     5     foo(n)
     6 foo(1)
     7 # 结果
     8 ...
     9 995
    10 996
    11 997
    12 报错信息:RecursionError: maximum recursion depth exceeded while calling a Python object
    View Code

    由此我们可以看出,未报错之前能看到的最大数字就是997.当然了,997是python为了我们程序的内存优化所设定的一个默认值,我们当然还可以通过一些手段去修改它:

    import sys
    print(sys.setrecursionlimit(100000))

    我们可以通过这种方式来修改递归的最大深度,刚刚我们将python允许的递归深度设置为了10w,至于实际可以达到的深度就取决于计算机的性能了。不过我们还是不推荐修改这个默认的递归深度。

    2.2、递归的应用示例

    示例1:

    已知alex比egon大两岁,egon比wusir大两岁,wusir比无alan大两岁,alan为40岁,求alex的年龄

     1  金鑫    40
     2 武sir    42
     3 egon    44
     4 alex     46

    根据几个人的关系,分析结果如下:

    age(4) = age(3) + 2     #alex的年龄
    age(3) = age(2) + 2     #egon
    age(2) = age(1) + 2     #wusir
    age(1) = 40             #alan

     因此,计算Alex年龄的递归函数如下:

    def age(n):
        if n == 1: return 40
        else: return age(n-1)+2
    print(age(4)) #46

     示例2:

    递归函数与三级菜单

    #三级菜单
    menu = {
        '北京': {
            '海淀': {
                '五道口': {
                    'soho': {},
                    '网易': {},
                    'google': {}
                },
                '中关村': {
                    '爱奇艺': {},
                    '汽车之家': {},
                    'youku': {},
                },
                '上地': {
                    '百度': {},
                },
            },
            '昌平': {
                '沙河': {
                    '老男孩': {},
                    '北航': {},
                },
                '天通苑': {},
                '回龙观': {},
            },
            '朝阳': {},
            '东城': {},
        },
        '上海': {
            '闵行': {
                "人民广场": {
                    '炸鸡店': {}
                }
            },
            '闸北': {
                '火车战': {
                    '携程': {}
                }
            },
            '浦东': {},
        },
        '山东': {},
    }
    三级菜单menu
    #递归函数实现三级菜单
    def threeLM(dic):
        while True:
            for k in dic:print(k)
            key = input('input>>').strip()
            #按b键返回上一级,按q键则退出函数
            if key == 'b' or key == 'q':return key
            elif key in dic.keys() and dic[key]:
                ret = threeLM(dic[key])
                if ret == 'q': return 'q'
    
    threeLM(menu)
    #结果如下
    北京
    上海
    山东
    input>>北京
    海淀
    昌平
    朝阳
    东城
    input>>海淀
    五道口
    中关村
    上地
    input>>五道口
    soho
    网易
    google
    input>>soho
    soho
    网易
    google
    input>>
    递归函数实现
    #堆栈实现三级菜单
    def StackThreeLM(dic):
        l = [menu]
        while l:
            for key in l[-1]:print(key)
            k = input('input>>').strip()   # 北京
            if k in l[-1].keys() and l[-1][k]:l.append(l[-1][k])
            elif k == 'b':l.pop()   #返回上一级
            elif k == 'q':break     #退出操作
    
    StackThreeLM(menu)
    利用堆栈实现

    二、二分查找算法

    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]
    比如从这个有序列表中,要查找66的索引,二分查找66索引位置的实现过程如下:

    二分查找算法代码如下:

    #二分查找算法
    def find(l,aim,start=0,end=None):
        if end == None:end = len(l)-1
        if start <= end:
            mid = (end - start) // 2  + start
            if l[mid] > aim:
                return find(l,aim,start=start,end=mid-1)
            elif l[mid] < aim:
                return find(l,aim,start=mid+1,end=end)
            elif l[mid] == aim:
                return mid
        else:
            return None
    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]
    print('ret :',find(l,66))    #ret : 17
    View Code
     
  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/lioushell/p/8480596.html
Copyright © 2011-2022 走看看