我试图使用dfs搜索在有向图中找到一个循环。我正在从包含顶点所有邻居的文本文件中读取文件。每当我调用cycle_exists方法时,我都会把它全部弄错,所以答案永远不会改变。
Vertex.py
"""
__version__ = 'October 2015'
Vertex class reads in our graph and
performs a depth first search on it
and performs the transitive closure operation.
Vertex class also checks for cycles in our graph.
"""
import sys
class Graph:
def __init__(self):
"""
Initialize the variable used in Graph
"""
self.dfsPaths = [] #list for dfsPaths
self.VertexList = {} #list for adjacent vertices
def readInputGraph(self, inputFile):
"""
Reads specified input file and stores in
adjacency list
:param inputFile: file to be rad in
:return: the VertexList
"""
file = open(inputFile, 'r') #open the file and read it
for line in file: #for each element in the file
(vertex,val) = line.split() #vertex gets first value in the line, val gets second
if vertex not in self.VertexList: #if vertex not in VertexList
self.VertexList[vertex] = set([val]) #add adjacent pairs
else: #else
self.VertexList.get(vertex).add(val) #add the values
for i in list(self.VertexList.keys()): #for each element in the list of the vertex keys
for j in self.VertexList[i]: # for each vertex that's in i
if j not in self.VertexList: #if j is not in the vertex list
self.VertexList[j] = set() #we add it to the vertex list
return self.VertexList #return list of adjacent vertices
def dfsSearch(self, graph, start, end, path = []):
"""
Performs a depth first search on
the graph that is read in from the file
:param graph: the graph that we are performing the search on
:param start: the starting vertex
:param end: the target vertex
:param path: a list of the paths
:return: the paths from the search
"""
path = path + [start] #path
if start == end: #if the start element and end element are the same
return [path] #return the list of paths
if start not in graph: #if the start element is not in the graph
print( 'Not Found')#prints out not found
return [] #return an empty list
paths = [] #path list
for node in graph[start]: #for node in the graph
if node not in path: #if not in the path
newpaths = self.dfsSearch(graph, node, end, path) #new paths we found
for newpath in newpaths: #for each new path in the list of new paths
paths.append(newpath) #add the new path to our list of paths
paths.sort() #sort our paths
self.cycle_exists(graph)
#print(self.cycle_exists(graph))
return paths #return our paths
def cycle_exists(self, graph): # -graph is our graph.
color = { node : "white" for node in graph} #color all nodes white to begin with
found_cycle = False # found_cycle set to false
for node in graph: # for each node in graph.
if color[node]:#if the color[node] is white
self.dfs_visit(graph, node, color, found_cycle) #we call the dfs_visit method
if found_cycle:#if a cycle is found
found_cycle = True
break#break
return found_cycle #return the true or false
def dfs_visit(self,graph, node, color, found_cycle):
#print(color)
if found_cycle: # if a cycle is found return to the cycle_exists method
return
color[node] = "gray"#else color the node gray
for neighbor in graph[node]: #for every neighbor in the graph of the node
if color[neighbor] == "gray": #If neighbor is gray
found_cycle = True # then a cycle exists.
return
if color[neighbor] == "white": #if the neighbor is white
#print(color[neighbor])
self.dfs_visit(graph, neighbor, color, found_cycle)# call dfs_visit .
color[node] = "black"# color the original node black
GraphDriver.py 来自Vertex import * import sys
class GraphDriver:
def __init__(self):
self.graph = Graph()
def main():
graph = Graph()
inFile = sys.argv[1]
d = graph.readInputGraph(inFile)
userInput = input("Enter a source and destination:")
dog = userInput.split(" ", -1)
for path in graph.dfsSearch(d, dog[0], dog[1]):
print(path)
if __name__ == '__main__':
main()
INPUT.TXT 0 1 0 6 1 2 1 5 2 3 2 4 4 3 4 0 5 4 6 5
答案 0 :(得分:0)
您的代码的问题在于它期望布尔变量 found_cycle
通过引用传递给 dfs_visit
。但是,Python 确实按值传递 (link, link)。因此,当 dfs_visit
将参数 found_cycle
设置为 True
时,此修改不会影响调用方传入 found_cycle
的 dfs_visit
变量。
您可以通过更改 dfs_visit
以返回是否找到循环来解决此问题:
def cycle_exists(self, graph):
color = { node : "white" for node in graph}
for node in graph:
if color[node] == "white":
if self.dfs_visit(graph, node, color):
return True
return False
def dfs_visit(self,graph, node, color):
color[node] = "gray"
for neighbor in graph[node]:
if color[neighbor] == "gray":
return True
if color[neighbor] == "white":
if self.dfs_visit(graph, neighbor, color):
return True
color[node] = "black"
return False
关于布尔变量的传递,请考虑以下示例:
def f(my_bool):
my_bool = True
my_bool = False
f(my_bool)
print(my_bool)
此代码将打印 False
。在全局范围内,变量 my_bool
用 False
初始化,然后传递给 f
。它是按值传递的,因此在 f
中,参数 my_bool
接收值 False
。但是,此变量 my_bool
与 my_bool
之外的变量 f
无关。因此修改 my_bool
中的 f
不会影响 my_bool
外的 f
。
请注意,这并不意味着您不能将引用传递给对象,只是该引用是按值传递的。考虑以下示例:
class MyObject:
def __init__(self):
self.x = 13
def f(my_object):
my_object.x = 17
def g(my_object):
my_object = MyObject()
my_object.x = 19
my_object = MyObject()
print(my_object.x)
f(my_object)
print(my_object.x)
g(my_object)
print(my_object.x)
这个例子打印:
13
17
17
在全局范围内,变量 my_object
使用 MyObject
的实例进行初始化。 MyObject
的构造函数将成员变量 x
初始化为 13
,这是第一个打印的值。然后将 my_object
变量传递给函数 f
。该变量是按值传递的,因此 my_object
中的变量 f
与全局作用域中的变量 my_object
是不同的变量。但是,两者都指向 MyObject
的同一个实例。因此,当 f
设置 my_object.x = 17
时,全局作用域中的下一个 print
将显示此值。
接下来,在全局范围内将变量 my_object
传递给 g
。同样,变量是按值传递的,所以 my_object
中的变量 g
与全局作用域中的变量 my_object
不同,但两者都指向 {{1} 的同一个实例}}。在 MyObject
中,g
变量被分配了一个新的 my_object
实例。这不会影响全局作用域中的 MyObject
,它仍然指向 my_object
的前一个实例。因此,全局作用域中的最后一个 MyObject
仍将显示已分配给 print
的第一个实例的 17
的 x
,而不是 {{1}在 MyObject
中分配给 19
的第二个实例中的 g
。
这就是为什么您的 x
变量不受与 MyObject
变量相同的问题的影响。对于 color
,对于 found_cycle
的每次调用都按值传递,对于 color
,但永远不会为 dfs_visit
中的 found_cycle
分配新值。因此,对 color
所做的修改与 dfs_visit
函数中原始 color
变量所指向的对象相同。