对于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。如果不满足此条件,函数将递归下去。如果最终还是不满足,可以再设置一个返回值。
写的内容有些乱,希望以后自己回顾时还能够看懂。