- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我需要转换
def aRecursive(n):
if n is 1:
return 3
else:
return 2 * aRecursive(n-1) + 5
分为 for 循环和 while 循环。我似乎无法全神贯注于这个过程。这些循环的原始函数是:
a(1) = 3
a(n) = 2 * a(n-1) + 5
答案和解释会有很大帮助。
最佳答案
我将提供一个基于函数调用方式的解决方案。该解决方案是通用的,因为您可以使用相同的方法将任何递归函数转换为迭代函数。理论上是可能的,但似乎没有人谈论如何实现。由于您的函数很简单,因此想出一个迭代函数并不难。但是二叉树的非递归后序遍历怎么样?如果您没有我将介绍的通用方法,您只能根据具体情况进行操作。
我们开始吧。首先,我们需要写下您的递归版本,并稍加更改以方便转换:
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
[start]: # here we create a label; not python, only for converting
if n == 1:
return 3
else:
return 2 * f(n-1) + 5
接下来我们将转换两件事:函数调用和返回语句。函数调用基本上分为两个步骤:将参数和返回地址压入堆栈并跳转到实际代码。 返回
基本上是弹出参数并跳转到保存的地址。那么我们开始吧:
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
[start]: # here we create a label; not python, only for converting
if n == 1:
return 3
else:
push(n) # push current parameter; since there is only one recursive function call in the body, we know where to return and there is no need to push the return address
n = n-1 # the next level actual parameter is now n-1
goto [start] # we go to the code of the function which is the start of this same function
return 2 * f(n-1) + 5 # we will never reach here... this line is where we need to return when any `return` statements is met
接下来我们将更改第一个 return
语句(return 3
):
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
[start]: # here we create a label; not python, only for converting
if n == 1:
res = 3
# for `return` we need to see if this is the top level or a inner recursive call
if stack is empty: # we are in top level
return res
# hey we are in a recursive call, and we need to return to the code after `goto`, why not move these code here?
else:
n = pop() # we pop the parameter saved
# this line is where we need to return when any `return` statements is met
return 2 * f(n-1) + 5
else:
push(n) # push current parameter; since there is only one recursive function call in the body, we know where to return and there is no need to push the return address
n = n-1 # the next level actual parameter is now n-1
goto [start] # we go to the code of the function which is the start of this same function
然后我们将转换返回2*f(n-1)+5
:
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
[start]: # here we create a label; not python, only for converting
if n == 1:
res = 3
if stack is empty:
return res
else:
[loop]:
n = pop() # we pop the parameter saved
# begin conversion of return
res = 2*res+5
if stack is empty:
return res;
else:
# we need to pop stack and jump to the same return, so we just jump to [loop]
goto [loop]
else:
push(n) # push current parameter; since there is only one recursive function call in the body, we know where to return and there is no need to push the return address
n = n-1 # the next level actual parameter is now n-1
goto [start] # we go to the code of the function which is the start of this same function
现在转换已经完成,我们需要简化这个困惑。首先我们应该考虑是否真的需要堆栈。对于这个特定问题,每次推送都会生成 n=n-1
,每次弹出都会生成 n=n+1
。所以实际上并不需要堆栈。
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
[start]: # here we create a label; not python, only for converting
if n == 1:
res = 3
if n == N: # SAME as stack is empty
return res # really return
else:
[loop]:
n = n+1 # WE JUST INCREASE N INSTEAD OF POP
res = 2*res+5
if n==N: # SAME as stack is empty
return res;
else:
goto [loop]
else:
# NO PUSH NEEDED
n = n-1 # the next level actual parameter is now n-1
goto [start]
堆栈被消除了,我们需要让这些goto
语句消失。请注意 [start]
标签和 goto [start]
构成了一个循环,我们只需将它们设为“while”循环即可:
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
# we reverse the if n==1 and make it a condition in while
while n != 1:
# NO PUSH NEEDED
n = n-1 # the next level actual parameter is now n-1
# you soon noticed the above calculation is not needed at all, it just sets n = 1
res = 3
if n == N:
return res
else:
[loop]:
n = n+1
res = 2*res+5
if n==N:
return res;
else:
goto [loop]
我们优化了第一个循环并将其替换为 n=1
。我们需要使 [loop]
和 goto [loop]
标记的第二个循环消失:
def f(N):
n = N # N is the top level parameter passed to this function
res = None # res is the result returned by this function
n = 1 # the result of the first while loop
res = 3
if n == N:
return res
else:
do: # Python does not have do while, but it is straight forward to do this convert
n = n+1
res = 2*res+5
while n!=N
return res
我们很快就会注意到前 4 条语句可以合并,并且我们删除所有评论:
def f(N):
n = 1
res = 3
if n == N:
return res
else:
do:
n = n+1
res = 2*res+5
while n!=N
return res
我们将反转 if n==N
语句:
def f(N):
n = 1
res = 3
if n != N:
do:
n = n+1
res = 2*res+5
while n!=N
return res
else:
return res
很明显,return res
可以放在顶层,if n!=N
和 do/while
循环可以放在顶层。组合成一个 while
循环:
def f(N):
n = 1
res = 3
while n != N:
n = n+1
res = 2*res+5
return res
这是原始递归函数的等效版本。请注意,我没有深入研究这个特定问题来提出这个版本,我只处理函数调用转换。我建议您在自己喜欢的文本编辑器中自行完成整个过程,这很有趣。你会发现它非常机械,唯一需要考虑的是堆栈的使用。其他技术,如“反转 if 条件”或“将 goto 转换为结构循环”非常简单。
有趣的是,迭代版本比仅基于转换过程的递归版本更高效,因为: 1. 我们消除了堆栈的使用; 2.我们消除了将n减少到1的循环。我们至少节省了一些CPU周期和堆栈存储。
关于python - 将递归函数转换为for循环和while循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46552499/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!