[英]Convert recursive function into a for loop and while loop
我需要轉換
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
接下來我們將轉換兩件事:函數調用和返回語句。 函數調用基本上分為兩步:將參數和返回地址推入堆棧並跳轉到實際代碼。 return
的基本就是pop參數,跳轉到保存的地址。 所以我們開始:
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
然后我們將轉換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:
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
這是原始遞歸函數的等效版本。 請注意,我沒有深入研究這個特定問題來提出這個版本,我只處理函數調用轉換。 我建議你在你最喜歡的文本編輯器中自己完成整個過程,這很有趣。 你會發現它非常機械,唯一需要考慮的是堆棧的使用。 其他技術,如“如果條件反轉”或“將 goto 轉換為結構循環”,則非常簡單。
有趣的是,迭代版本比僅基於轉換過程的遞歸版本更有效,因為: 1. 我們消除了堆棧的使用; 2. 我們消除了將 n 減少到 1 的循環。我們至少節省了一些 CPU 周期和堆棧存儲。
一種可能的for
循環:
def a(n):
answer = 3
for i in range(n - 1):
answer = answer * 2 + 5
return answer
一個可能的while
循環,雖然我並不特別喜歡while
這里使用while
:
def a(n):
answer = 3
while n > 1:
answer = answer * 2 + 5
n -= 1
return answer
請注意,這些答案(或您的原始代碼)都沒有處理小於 1 的n
。
a(1) = 3
a(n) = 2 * a(n - 1) + 5
因此,如果您要計算a(5)
,則有兩種合理的方法。 一種是寫出遞歸的東西:
a(5) = 2 * a(4) + 5
然后計算a(4)
:
a(4) = 2 * a(3) + 5
所以a(5)
現在是:
a(5) = 2 * (2 * a(3) + 5) + 5
你可以繼續這個過程,直到你不再有任何對a
引用,然后你就可以做算術了。
非遞歸方式是向上計數:
a(1) = 3
a(2) = 2 * a(1) + 5 = 2 * 3 + 5 = 11
a(3) = 2 * a(2) + 5 = 2 * 11 + 5 = 27
a(4) = 2 * a(3) + 5 = 2 * 27 + 5 = 59
a(5) = 2 * a(4) + 5 = 2 * 59 + 5 = 123
這樣,您從 3 開始,然后在每個步驟中乘以 2 並加上 5 以獲得下一個數字。 當你達到你試圖計算其函數的n
時就停止。
第二種(非遞歸)方法是上述for
和while
循環的工作方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.