DFS - 实现O(| E |)时序复杂度解决方案

时间:2015-07-17 05:55:36

标签: python algorithm graph-algorithm

我正在尝试实现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 ......来回......

1 个答案:

答案 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)最坏情况。