我正在尝试实现DFS,但根据A StackOverFlow link about DFS,DFS仅使用Stack。
这是我目前的实施:
def DFS_graph_recursive(graph, start, end, stack):
#Stack to push the node when we are entering the node
stack.append(start)
while(end not in stack):
for i in graph.edges[start]:
#check if this is inside the stack, to make sure that it doesn't try to go back
if (i not in stack):
#Recursive Call
DFS_graph_recursive(graph, i, end, stack)
#Pop the stack when we are leaving this node, but need to make sure if end is inside
if(end not in stack):
stack.pop()
存在一些问题,时间复杂度看起来不像O(| E |)。第一个while循环是O(| E |),但是,我需要检查我的下一个节点是否已经在堆栈内,以避免倒退,如果这个堆栈很大,我认为i not in stack
需要O(n)进行计算,使得该算法在复杂度上看起来像O(| E | ^ 2)。
if(end not in stack)
使得算法在时间复杂度方面变得更糟,因为对于每个边缘搜索,它需要检查结束是否在堆栈中,这意味着如果我们发现我们不想弹出堆栈一个办法。这进一步将时间复杂度增加到O(| E | ^ 2 + | E |)。有没有办法只用一个while循环来做到这一点?
就空间复杂度而言,最坏的情况应该是O(| V |),我们有一个分支因子为1的长树。
如果它是一个二叉树类型,我可以很容易地实现一个O(| E |)解决方案,它有一个定向路径下行到子节点。问题是因为问题是无向图,所以假设有两个顶点,A和B.如果A连接到B,那么B连接到A.所以,如果我不检查if (i not in stack)
我将是卡住从A到B,从B到A ......来回......
答案 0 :(得分:1)
使用此算法,您实际上最终将多次转到同一节点(i not in stack
的复杂性是一个额外的问题)
您应该考虑保留visited
列表/字典,以跟踪您访问过的节点。如果您访问过该节点,那么您不会在堆栈中推送它。代码就像 -
vis = {}
def DFS_graph(graph, start, end, stack):
#Stack to push the node when we are entering the node
stack.append(start)
vis[start] = 1
while len(stack):
# got to an element
found_element = stack[-1]
if found_element == end:
# you found the end, so break now
break
stack.pop()
for i in graph.edges[start]:
#check if this is inside the stack, to make sure that it doesn't try to go back
if i not in vis:
#Recursive Call
stack.push(i)
这里我使用的是一个字典,其中if i not in vis
的实际复杂性在最坏情况下应为O(n),在平均情况下应为O(1)。
如果您将图形节点表示为g[0], g[1], g[2] ....
,那么您可以使用列表将复杂性变为O(1)最坏情况。