python-3.x - return 语句如何在递归函数中工作?
问题描述
我找到了一个代码来检查给定的图形是否是一棵树
# Python Program to check whether
# a graph is tree or not
from collections import defaultdict
class Graph():
def __init__(self, V):
self.V = V
self.graph = defaultdict(list)
def addEdge(self, v, w):
# Add w to v ist.
self.graph[v].append(w)
# Add v to w list.
self.graph[w].append(v)
# A recursive function that uses visited[]
# and parent to detect cycle in subgraph
# reachable from vertex v.
def isCyclicUtil(self, v, visited, parent):
# Mark current node as visited
visited[v] = True
# Recur for all the vertices adjacent
# for this vertex
for i in self.graph[v]:
# If an adjacent is not visited,
# then recur for that adjacent
if visited[i] == False:
if self.isCyclicUtil(i, visited, v) == True:
return True
# If an adjacent is visited and not
# parent of current vertex, then there
# is a cycle.
elif i != parent:
return True
return False
# Returns true if the graph is a tree,
# else false.
def isTree(self):
# Mark all the vertices as not visited
# and not part of recursion stack
visited = [False] * self.V
# The call to isCyclicUtil serves multiple
# purposes. It returns true if graph reachable
# from vertex 0 is cyclcic. It also marks
# all vertices reachable from 0.
if self.isCyclicUtil(0, visited, -1) == True:
return False
# If we find a vertex which is not reachable
# from 0 (not marked by isCyclicUtil(),
# then we return false
for i in range(self.V):
if visited[i] == False:
return False
return True
# Driver program to test above functions
g1 = Graph(5)
g1.addEdge(0, 1)
g1.addEdge(1, 2)
g1.addEdge(2, 3)
g1.addEdge(2, 4)
g1.addEdge(0, 4)
if (g1.isTree()):
print("Graph is a tree")
else:
print("Graph is not a tree")
在第四次迭代期间,即 v = 3,parent = 2
def isCyclicUtil(self, v, visited, parent): #(3,visited,2)
visited[v] = True
for i in self.graph[v]: #when the for loop breaks
if visited[i] == False:
if self.isCyclicUtil(i, visited, v) == True:
return True
elif i != parent:
return True
return False #Why is that the return condition returns to the previous for loop when the
#return statement is False and when it is True it returns to the calling function
返回时为 False
#vi is visited #cy is iscycleutil()
_ _ _ _ _ _ _ _ _ _
0,vi,-1 _>(1,vi,0) _>(2,visited,1)| _>(3,vi,2) |
{ | { | { | | { |
cy(i,vi,v)_| cy(i,vi,v)_| for loop <__| | return False_|
} } cy(i,vi,v)_| }
)
例如,当返回 True(用于实验)
0,vi,-1 _>(1,vi,0) _>(2,visited,1) _>(3,vi,2)
{ | { | { | {
cy(i,vi,v)_| cy(i,vi,v)_| for loop | return True__
} } cy(i,vi,v)_| } |
) return True<______________|
为什么return语句为False时返回条件返回前一个for循环,为True时返回调用函数。
谁能澄清我的疑问。
提前感谢您的帮助
解决方案
'return' 总是终止函数的当前激活并将控制权返回到调用它的点。
那么,在递归函数中,您可以将激活想象为一个“嵌套”在另一个内部。将它们编号为 0、1、……如果我们在 isCyclicUtil 的激活 N 中,并且我们调用 isCyclicUtil,那么这将创建激活 N+1。
当在激活 N+1 中执行返回时,它精确地返回到激活 N 中的调用。
这与非递归函数没有什么不同。如果函数 X 调用函数 Y,并且函数 Y 执行“return”,则控制权返回到函数 X(紧接在调用 Y 的点之后)。
对于递归调用,X 和 Y 是同一个函数,但是调用和返回的规则没有改变。
在您的特定情况下,递归调用位于 for 循环的中间,因此当内部调用返回时,控制返回到该位置。如果内部调用返回的值为真,那么外部调用立即返回给它的调用者,从而终止循环。
所以返回总是返回到同一个地方,这就是之后发生的事情(直接调用者对返回值所做的事情),这会有所不同。
我在您的代码中添加了很多打印语句(非常hacky,没有干净地完成)
isCyclic called with v=0 at depth 0
loop at depth 0, i=1, v=0, visited[i]=False
isCyclic called with v=1 at depth 1
loop at depth 1, i=0, v=1, visited[i]=True
loop at depth 1, i=2, v=1, visited[i]=False
isCyclic called with v=2 at depth 2
loop at depth 2, i=1, v=2, visited[i]=True
loop at depth 2, i=3, v=2, visited[i]=False
isCyclic called with v=3 at depth 3
loop at depth 3, i=2, v=3, visited[i]=True
at end, return from depth 3
nested call returned False
loop at depth 2, i=4, v=2, visited[i]=False
isCyclic called with v=4 at depth 3
loop at depth 3, i=2, v=4, visited[i]=True
loop at depth 3, i=0, v=4, visited[i]=True
not parent, returning from depth 3
nested call returned True
returning from depth 2
nested call returned True
returning from depth 1
nested call returned True
returning from depth 0
这样做之后,我看到了我应该一直看到的东西。您认为当内部调用返回 True 时,它会以某种方式一直返回。但实际发生的是控制权(当然)返回给直接调用者,然后(因为返回为真)然后返回给它的直接调用者,依此类推。
注释代码的主要部分:
def isCyclicUtil(self, v, visited, parent):
global depth
depth = depth+1
print("isCyclic called with v=%d at depth %d" % (v, depth))
# Mark current node as visited
visited[v] = True
# Recur for all the vertices adjacent
# for this vertex
for i in self.graph[v]:
print(" loop at depth %d, i=%d, v=%d, visited[i]=%s" % (depth,i,v, visited[i]))
# If an adjacent is not visited,
# then recur for that adjacent
if visited[i] == False:
temp = self.isCyclicUtil(i, visited, v)
print(" nested call returned %s" % temp)
if temp == True:
print("returning from depth %d" % depth)
depth = depth-1
return True
# If an adjacent is visited and not
# parent of current vertex, then there
# is a cycle.
elif i != parent:
print("not parent, returning from depth %d" % depth)
depth = depth-1
return True
print("at end, return from depth %d" % depth)
depth = depth-1
return False
推荐阅读
- assembly - 8085中不同寄存器的初始值是多少?
- c++ - 如何完全停止 QTimer
- pandas - (Pandas Dataframes)如何让行从具有重复列名的数据框中共享同一列
- python - 如果python正在复制一个对象,如何停止它?
- python - 在 Python 中连接 2 个列表的运行时
- python - 为什么我的计算不能在另一个函数中调用的函数中执行?
- react-native - React Native,Formik-Yup 验证的错误未显示
- c# - C# 类型名称未知但已声明
- c# - 如何仅在 azure devops CI env 中而不是在本地运行一些 NUnit 测试
- python - 如何在 Pandas 中使用非数字数据做数据透视表?