python如何实现递归转非递归
先说总结,这种方案总的来说就是机械化的强转,时间复杂度和空间复杂度没什么变化,唯二的优点可能是1.不会爆栈,2.节省了函数调用的开销
而且最终产出的代码效果不那么美观,比较冗长
思路是:当发生递归调用时,模拟函数调用的压栈。并处理入参和返回值和记录返回到当前栈的时候该继续从哪里执行
以如下递归(leetcode爬楼梯)为例
deff(n): ifn<=2: returnn returnf(n-1)+f(n-2)
第一步:
将涉及到递归调用的,单独变成最简单的一行
deff(n): ifn<=2: returnn a=f(n-1) b=f(n-2) returna+b
第二步:
我们需要模拟递归栈调用,当执行完递归回到当前栈的时候需要知道从哪里继续执行,所以需要一个flag标记,开始的时候为0,我们先手工标记一下,再后序转换的时候可以方便查看
deff(n): ifn<=2: returnn a=f(n-1) #flag1 b=f(n-2) #flag2 returna+b
第三步:
构建解题模版
deff_iter(n): stack=[] #入参,接收递归调用的(a,b),flag base_frame=[None,{'a':None,'b':None},0] first_frame=[(n,'a'),{},0] stack.append(base_frame) stack.append(first_frame) whilelen(stack)>1: arg,local,flag=stack[-1] arg,aorb=arg ifflag==0: pass elifflag==1: pass elifflag==2: pass returnstack[0][-2]['a']
first_frame=[(n,'a'),{},0]注意此时接收函数返回的时候为什么是一个字典,并且调用参数的时候传参多了一个'a',因为函数被递归调用了两次,分别得到一个a和b,所以在返回的时候需要知道返回是给a还是给b,如果只递归调用了一次,那么就不需要带上'a',返回的时候也不用是字典了,最后整个函数执行完成之后,base_frame里面就是最终的答案
第四步:
填充骨架,记住两点就可以了
函数调用的时候,先将当前栈的flag修改(等再次执行到当前栈的时候知道从哪里继续执行)
发生return的时候stack.pop出栈后,将结果写入栈顶的结果字典
其他照抄就行
deff_iter(n): stack=[] #入参,局部变量(a,b),flag base_frame=[None,{'a':None,'b':None},0] first_frame=[(n,'a'),{},0] stack.append(base_frame) stack.append(first_frame) whilelen(stack)>1: arg,local,flag=stack[-1] arg,aorb=arg ifflag==0: ifarg<=2: stack.pop() stack[-1][-2][aorb]=arg else: stack[-1][-1]=1 new_frame=[(arg-1,'a'),{},0] stack.append(new_frame) elifflag==1: stack[-1][-1]=2 new_frame=[(arg-2,'b'),{},0] stack.append(new_frame) elifflag==2: a,b=local['a'],local['b'] stack.pop() stack[-1][-2][aorb]=a+b returnstack[0][-2]['a']
完结,撒花:tada:
另外:有一些函数编程语言,能将所有的递归调用转化成尾调用(非尾递归),这样就不会发生爆栈的问题,但是目前流行的大多数语言都是没有这个功能的
附加练习
有兴趣可以自己按步骤试一试,如有见解,欢迎探讨:clap:
二叉树中序遍历
递归版本
classNode: def__init__(self,val): self.val=val self.left=None self.right=None deflist2tree(l): iflen(l)==1: returnNode(l[0]) mid=(len(l)-1)>>1 root=Node(l[mid]) root.left=list2tree(l[:mid]) root.right=list2tree(l[mid+1:]) returnroot definorder_recursive(root): ifnotroot: return[] returninorder_recursive(root.left)+[root.val]+inorder_recursive(root.right) l=list(range(1,2<<2)) tree=list2tree(l) c=inorder_recursive(tree) print(c)
非递归版本
classNode: def__init__(self,val): self.val=val self.left=None self.right=None deflist2tree(l): stack=[] #(root,left_right),{'a':,'b':},flag base_frame=[None,{},0] first_frame=[(l,'a'),{},0] stack.append(base_frame) stack.append(first_frame) whilelen(stack)>1: cur=stack[-1] arg,local,flag=cur arg,aorb=arg mid=(len(arg)-1)>>1 ifflag==0: iflen(arg)==1: stack.pop() stack[-1][-2][aorb]=Node(arg[0]) else: stack[-1][-1]=1 new_frame=[(arg[:mid],'a'),{},0] stack.append(new_frame) elifflag==1: stack[-1][-1]=2 new_frame=[(arg[mid+1:],'b'),{},0] stack.append(new_frame) elifflag==2: left,right=local['a'],local['b'] root=Node(arg[mid]) root.left=left root.right=right stack.pop() stack[-1][-2][aorb]=root returnstack[0][-2]['a'] definorder_recursive(root): stack=[] base_frame=[None,{},0] first_frame=[(root,'a'),{'a':None,'c':None},0] stack.append(base_frame) stack.append(first_frame) whilelen(stack)>1: cur=stack[-1] arg,local,flag=cur arg,left_right=arg ifflag==0: ifnotarg: stack.pop() stack[-1][-2][left_right]=[] else: stack[-1][-1]=1 new_frame=[(arg.left,'a'),{},0] stack.append(new_frame) elifflag==1: stack[-1][-1]=2 new_frame=[(arg.right,'c'),{},0] stack.append(new_frame) elifflag==2: b=[arg.val] ret=local['a']+b+local['c'] stack.pop() stack[-1][-2][left_right]=ret returnstack[0][-2]['a'] l=list(range(1,2<<2)) tree=list2tree(l) c=inorder_recursive(tree) print(c)
以上就是python如何实现递归转非递归的详细内容,更多关于python递归转非递归的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。