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。如果不满足此条件,函数将递归下去。如果最终还是不满足,可以再设置一个返回值。

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

posted @ 2017-12-25 15:39  roadcode  阅读(389)  评论(0编辑  收藏  举报