• python初学 数据分叉情况下的函数递归


    对于python中的函数递归,其实用while和for循环可以等价的实现。平时较少用到,但是在某些特定情况下比较方便实现一些功能。

    对于没有数据分叉的函数递归,比较简单。如:

    def cal(n):
        print(n)
        if n > 0:
            return cal(int(n/2))
        else:
            return 'n=0 done'
        
    print(cal(10))
    
    输出:
    10
    5
    2
    1
    0
    n=0 done

    通过层层调用,达到条件后,结束调用,再层层返回。

    但是对于有数据分叉的函数递归,如对嵌套列表的遍历、查询,就会比较绕一些

    先看没有分叉的: 

    给定一个节点,在menus找到他,如果该节点存在,打印出来,并返回true,如果不存在,就返回false
    menus = [
    {
    'text': '北京',
    'children':[
    {'text':'昌平','children':[
    {'text':'沙河','children':[]}
    ]}]}]

    def find_menu(menu,city):
    if menu:
    for i in menu:
    if i['text'] != city:
    return find_menu(i['children'],city) #如果本层没有city,则会深入到下一层
    else:
    print(city)
    return True
    else:
    return False

    city=input('>>>>')
    print(find_menu(menus,city))

    可以看到比较容易就实现了。
    但是这里menus有一个特点,就是每一级menus都只有一个元素,找过这个元素,本级就找完了。如果有多个元素呢?这就意味着,你把元素1里面嵌套的元素遍历一遍之后,还需要回头去找元素2但是如果把meuns改变一下,难度就会大大增加。
    menus = [
        {
            'text': '北京',
            'children':[
                {'text':'朝阳','children':[]},
                {'text':'昌平','children':[
                    {'text':'沙河','children':[]},
                    {'text':'回龙观','children':[]},
                ]},
            ]
        },
        {
            'text':'上海',
            'children':[
                {'text':'宝山','children':[]},
                {'text':'金山','children':[]}
            ]
        }
    ]

     对于这个menus,如果我们继续用刚才的递归函数,就会达不到目的。

    def find_menu(menu,city):
        if menu:
            for i in menu:
                if i['text'] != city:
                   return find_menu(i['children'],city)  #如果本层没有city,则会深入到下一层
                else:
                    print(city)
                    return True
        else:
            return False
    city=input('>>>>')
    print(find_menu(menus,city))
    
    >>>>朝阳
    朝阳
    True
    
    >>>>沙河
    False
    
    >>>>宝山
    False

     可以看到,只有在找每级的第一个元素,即menus[0][0]...才可以,其余的全部都会返回False。这是因为,使用for循环,在每级都是从第一个元素开始找,找不到,就会递归至下一级的for循环,依然从下一级的第一个元素开始找起,直到最后一层,如何还是没有找到,就会return False,返回返回上一级。上一级继续执行retur语句,返回False,再返回上一级。以此类推,直到完全退出。这里我们发现,for循环根本就没有执行完,就直接退出了程序,达不到遍历的效果。

    如果想将for循环进行完,就不能在find_menu(menus,city)前使用return,就不能将返回值一层一层向上传递,同样是不行的。

    换个角度思考,什么时候可以结束for循环呢,就是找到 city情况下。如果找不到city,我们就需要让for循环一直执行下去,直到执行完,还是找不到的话,就说明没有city,这时可以返回false。

    这么我们可以加一个条件语句,

    if 找到了city

      就return

    那么可以把代码改一下:

    def find_menu(city,menu):
        if menu:
            for i in menu:
                if i['text'] != city:
                     flag=find_menu(city,i['children'])
                     if flag==True:
                        return True
                else:
                    print(city)
                    return True
            else:
                return False
        else:
            return False        

    可以以最后find_menu的执行结果来判断,如果找到了city,find_menu就会返回True。如何把这个值一层一层传上去呢。我们可以让一个参数来接收返回值,并逐级上传。

    也可以去掉这个参数,直接用find_menu的值。

     由于menu为空的话, 肯定是没有找到city,for循环肯定也是执行完了,所以与最外层if对应的else也可以去掉。因为for--else已经返回了false。

    def find_menu(city,menu):
        if menu:
            for i in menu:
                if i['text'] != city:
                    if find_menu(city,i['children']):
                        return True
                else:
                    print(city)
                    return True
            else:
                return False

     这样就完成了一个有数据分叉的函数递归问题。

    总结一下,使用函数递归,要紧盯使函数递归结束的条件,在此条件下,使用return。如果不满足此条件,函数将递归下去。如果最终还是不满足,可以再设置一个返回值。

    写的内容有些乱,希望以后自己回顾时还能够看懂。

  • 相关阅读:
    对PostgreSQL的 seq scan , bitmap index scan 和 index scan 的进一步理解
    C# IEnumerable和IEnumerator的区别,如何实现
    老板运煤问题及解决方案
    快速排序和简单排序
    给定数组,查找最小的k个元素或最大的k个元素
    一列数字的规则如下;1,1,2,3,5,8,13,21,34........ 求第30位数字是多少,用递规和非递归两种方法算法实现
    C# 如何利用反射来加载程序集,并调用程序集中有关类的方法
    http 请求 header 应用分析
    templatemonster 10231 面朝大海 你听到什么?
    足球俱乐部 网站模板 附带源文件 字体
  • 原文地址:https://www.cnblogs.com/ohahastudy/p/8109675.html
Copyright © 2020-2023  润新知