微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

深度优先搜索,使用堆栈进行发现和完成时间,但无递归 关于递归解决方案关于迭代解

如何解决深度优先搜索,使用堆栈进行发现和完成时间,但无递归 关于递归解决方案关于迭代解

我正在实现深度优先搜索算法。有两个要求:我必须使用堆栈(无递归),并且它还应该返回发现时间和完成时间。这是我实现的使用递归的代码

def dfs(graph,source):
    """Depth-first search algorithm

    This function computes depth-first search and prints the nodes as it travels

    Arguments:
        graph: List[List[int]],adjacency matrix of the graph
        source: int,the starting point
    Returns:
        None
    """
    visited = [False] * len(graph)
    time_start = [0] * len(graph) # Time when vertex is discovered
    time_finish = [0] * len(graph) # Time when vertex has finished discovering
    time = 0
    dfs_visit(graph,source,visited,time,time_start,time_finish)
    return time_start,time_finish

def dfs_visit(graph,time_finish):
    time += 1
    time_start[source] = time
    visited[source] = True
    print(source,end = " ")
    for i,val in enumerate(graph[source]):
        if not visited[i] and val != 0:
            dfs_visit(graph,i,time_finish)
    time += 1
    time_finish[source] = time

样本输入:

graph = [[0,1,0],[1,1],[0,1]]

预期输出2 0 1 3 ([2,3,2],[3,4,2,3]),其中第一个数组指示发现时间,第二个数组指示完成时间(按索引)。

有了这个想法,我就使用Stack实现了DFS:

def dfs_stack(graph,source):
    """Depth-first search algorithm using stack

    This function computes depth-first search and prints the nodes as it travels

    Arguments:
        graph: List[List[int]],the starting point
    Returns:
        None
    """
    visited = [False] * len(graph)
    dfs_visit(graph,visited)
    return time_start,visited):
    stack = []
    stack.append(source)

    while (len(stack)):
        s = stack[-1]
        stack.pop()
        if not visited[s]:
            print(s,end = " ")
            visited[s] = True
        for idx,val in enumerate(graph[s]):
            if (not visited[idx]) and val != 0:
                stack.append(idx)

我尝试用time += 1; time_start[s] = ...来计算这些时间,但它输出的结果很奇怪。我应该在哪里正确放置时间计数器?

解决方法

关于您的代码的几句话:

关于递归解决方案

记录的时间有些混乱,因为您有重复的时间戳记(例如3)。这是因为您对time进行的递增不会反馈给调用方,后者具有自己的time变量实例。我会将time设为非局部变量,以使其不断增加。

所以我将其更改为:

def dfs(graph,source):
    def dfs_visit(graph,source,visited,time_start,time_finish):
        nonlocal time
        time += 1
        time_start[source] = time
        visited[source] = True
        print(source,end = " ")
        for i,val in enumerate(graph[source]):
            if not visited[i] and val != 0:
                dfs_visit(graph,i,time_finish)
        time += 1
        time_finish[source] = time

    visited = [False] * len(graph)
    time_start = [0] * len(graph)
    time_finish = [0] * len(graph)
    time = 0
    dfs_visit(graph,time_finish)
    return time_start,time_finish

现在print(dfs(graph,2))的输出将是:

2 0 1 3 ([2,3,1,6],[5,4,8,7])

这对我来说更有意义,但也许我误解了您打算使用time做些什么。

关于迭代解

  • s = stack[-1]后跟stack.pop()可以写成s = stack.pop()

  • 您正在将节点的所有个子代推入堆栈,然后再处理它们的子代。这意味着,深度优先遍历实际上将从后到先访问子级,而递归实现则是从最后到最后地访问子级。

记录完成时间

现在是您问题的核心。如果要记录访问的结束时间,则需要留下堆栈上的节点的痕迹,并且仅在处理完所有子节点之后才将其从该堆栈中删除。不早。

实现该目标的一种方法是,将最后一个从节点访问的邻居存储在堆栈中。因此,您将存储(节点,邻居)元组。如果尚未从该节点访问下一个节点,则neighbor的初始值可能为-1。

这是如何工作的:

def dfs_stack(graph,source):
    visited = [False] * len(graph)
    time_start = [0] * len(graph)
    time_finish = [0] * len(graph)
    time = 0
    stack = [(source,-1)]
    while stack:
        node,neighbor = stack.pop()
        if neighbor == -1:
            if visited[node]:
                continue
            visited[node] = True
            print(node,end = " ")
            time += 1
            time_start[node] = time
        try:
            neighbor = graph[node].index(1,neighbor + 1)
            stack.append((node,neighbor))
            if not visited[neighbor]:
                stack.append((neighbor,-1))
        except ValueError:  # no more neighbors...
            time += 1
            time_finish[node] = time

如果我们用print(dfs_stack(graph,2))进行调用,我们还会得到:

2 0 1 3 ([2,7])

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。