时间:2010-07-26 07:24:04

标签: algorithm graph-algorithm graph-theory depth-first-search breadth-first-search

14 个答案:

答案 0 :(得分:279)

答案 1 :(得分:104)

深度优先搜索

深度优先搜索通常用于模拟游戏(以及现实世界中类似游戏的情况)。在典型的游戏中,您可以选择几种可能的操作之一。每种选择都会带来进一步的选择,每种选择都会导致进一步的选择,以此类推,形成一种不断扩展的树形可能性图。

enter image description here

例如在像Chess,tic-tac-toe这样的游戏中,当你决定做出什么动作时,你可以在心理上想象一个动作,然后你的对手可能的反应,然后是你的反应,等等。您可以通过查看哪一步可以获得最佳结果来决定做什么。

只有游戏树中的某些路径才能赢得胜利。有些会导致你的对手获胜,当你达到这样的结局时,你必须备份或回溯到前一个节点并尝试不同的路径。通过这种方式,您可以探索树,直到找到成功结束的路径。然后你沿着这条路走第一步。

广度优先搜索

广度优先搜索有一个有趣的属性:它首先找到距起点一个边的所有顶点,然后找到两个边距离的所有顶点,依此类推。如果您试图找到从起始顶点到给定顶点的最短路径,这将非常有用。您启动BFS,当您找到指定的顶点时,您知道到目前为止您已跟踪的路径是该节点的最短路径。如果路径较短,BFS就已经找到了。

广度优先搜索可用于查找对等网络中的邻居节点,如BitTorrent,GPS系统以查找附近位置,社交网站可查找指定距离内的人员等等。

答案 2 :(得分:100)

很好的解释来自 http://www.programmerinterview.com/index.php/data-structures/dfs-vs-bfs/

  

BFS的一个例子

以下是BFS的外观示例。这类似于Level Order Tree Traversal,我们将使用QUEUE和ITERATIVE方法(大多数RECURSION将以DFS结束)。数字表示在BFS中访问节点的顺序:

enter image description here

在深度优先搜索中,从根开始,并尽可能地跟随树的一个分支,直到找到您要查找的节点或者您到达叶节点(没有子节点的节点) )。如果您点击叶子节点,则继续搜索最近的祖先与未探测的孩子。

  

DFS的一个例子

以下是DFS的外观示例。我认为二叉树中的发布顺序遍历将首先从Leaf级别开始工作。数字表示在DFS中访问节点的顺序:

enter image description here

  

DFS和BFS之间的差异

比较BFS和DFS,DFS的一大优势是它比BFS具有更低的内存要求,因为没有必要在每个级别存储所有子指针。根据数据和您要查找的内容,DFS或BFS可能是有利的。

例如,给定一个家谱,如果一个人在树上寻找仍然活着的人,那么可以安全地假设该人将在树的底部。这意味着BFS需要很长时间才能达到最后一级。但是,DFS会更快地找到目标。但是,如果一个人正在寻找一个很久以前去世的家庭成员,那么这个人就会更接近树顶了。然后,BFS通常比DFS快。因此,两者的优势因数据和您正在寻找的内容而异。

另一个例子是Facebook;对朋友之友的建议。我们需要直接的朋友来建议我们可以使用BFS。可能是找到最短路径或检测周期(使用递归)我们可以使用DFS。

答案 3 :(得分:33)

答案 4 :(得分:23)

答案 5 :(得分:12)

当你作为一个程序员来处理这个问题时,一个因素是突出的:如果你正在使用递归,那么深度优先搜索更简单来实现,因为你不需要维护包含尚待探索的节点的附加数据结构。

如果你在节点中存储“已访问过的”信息,这里是深度优先搜索非定向图:

def dfs(origin):                               # DFS from origin:
    origin.visited = True                      # Mark the origin as visited
    for neighbor in origin.neighbors:          # Loop over the neighbors
        if not neighbor.visited: dfs(next)     # Visit each neighbor if not already visited

如果将“已访问”信息存储在单独的数据结构中:

def dfs(node, visited):                        # DFS from origin, with already-visited set:
    visited.add(node)                          # Mark the origin as visited
    for neighbor in node.neighbors:            # Loop over the neighbors
        if not neighbor in visited:            # If the neighbor hasn't been visited yet,
            dfs(node, visited)                 # then visit the neighbor
dfs(origin, set())

将此与广度优先搜索进行对比,无论如何,您需要为尚未访问的节点列表维护单独的数据结构。

答案 6 :(得分:12)

BFS的一个重要优点是它可以用于查找未加权图中任意两个节点之间的最短路径。 鉴于,we cannot use DFS for the same

答案 7 :(得分:6)

对于BFS,我们可以考虑Facebook的例子。我们收到来自其他朋友个人资料的FB个人资料中添加朋友的建议。假设A-> B,而B-> E和B-> F,所以A将得到E和F的建议。它们必须使用BFS读取到第二级。 DFS更基于我们想要根据从源到目的地的数据预测某些内容的场景。如前所述,国际象棋或数独游戏。 一旦我在这里有不同的东西,我相信DFS应该用于最短路径,因为DFS将覆盖整个路径然后我们可以决定最好的。但是,由于BFS将使用贪婪的方法,所以它看起来可能是最短路径,但最终结果可能会有所不同。 让我知道我的理解是否错误。

答案 8 :(得分:4)

答案 9 :(得分:1)

由于Depth-First Searches在处理节点时使用堆栈,因此DFS提供了回溯。因为广度优先搜索使用队列而不是堆栈来跟踪处理的节点,所以BFS不提供回溯。

答案 10 :(得分:1)

当树宽度非常大且深度较低时,使用DFS作为递归堆栈不会溢出。当宽度较低且深度非常大以遍历树时使用BFS。

答案 11 :(得分:1)

以下是您所要询问的全面答案。

简单来说:

广度优先搜索(BFS)算法,从其名称“广度”开始,通过节点的外边缘发现节点的所有邻居,然后通过其外边缘发现先前提到的邻居的未访问邻居,依此类推,直到访问了原始来源可访问的所有节点(如果还有其他未访问的节点等等,我们可以继续并采用另一个原始来源)。因此,如果边缘的权重相同,则可以使用它找到从一个节点(原始源)到另一个节点的最短路径(如果有)。

深度优先搜索(DFS)算法从其名称“深度”开始,通过其外边缘发现了最近发现的节点x的未访问邻居。如果没有来自节点x的未访问邻居,则该算法回溯以发现从中发现节点x的节点的未访问邻居(通过其外部边缘),依此类推,直到访问了可从原始源到达的所有节点为止。 (如果还有其他未访问的节点,我们可以继续并采用其他原始资源,等等)。

BFS和DFS都可能不完整。例如,如果节点的分支因数是无限的,或者对于要支持的资源(内存)来说很大(例如,当存储下一个要发现的节点时),那么即使搜索的键距一定距离,BFS也不会完成原始来源的一些边缘。此无限分支因子可能是由于要从给定节点进行发现而进行的无限选择(相邻节点)。 如果深度是无限的,或者对于要支持的资源(内存)来说很大(例如,当存储下一个要发现的节点时),那么即使搜索到的密钥可以是原始数据源的第三个邻居,DFS也不会完成。这种无限的深度可能是由于这样一种情况,对于该算法发现的每个节点,至少存在一个以前没有访问过的新选择(邻居节点)。

因此,我们可以得出何时使用BFS和DFS的结论。假设我们正在处理一个可管理的有限分支因子和一个可管理的有限深度。如果搜索到的节点较浅,即在从原始源经过一些边缘之后可以到达,则最好使用BFS。另一方面,如果搜索到的节点较深,即在从原始来源经过很多边缘之后即可到达,则最好使用DFS。

例如,在社交网络中,如果我们要搜索与某个特定人具有相似兴趣的人,则可以将这个人的BFS用作原始来源,因为这些人大多是他的直接朋友或朋友朋友,即一两个边缘。 另一方面,如果我们要搜索与特定人的兴趣完全不同的人,则可以将此人的DFS用作原始来源,因为这些人大多与他相距很远,即朋友的朋友的朋友....即边缘太多。

BFS和DFS的应用程序也可能会有所不同,这是因为每个文件搜索的机制。例如,当我们只想检查从一个节点到另一个节点的可达性而又不知道该节点的位置时,可以使用BFS(假设分支因子是可管理的)或DFS(假设深度是可管理的)。他们俩也都可以解决相同的任务,例如图形的拓扑排序(如果有)。 BFS可用于查找从一个节点(原始源)到另一个节点的最短路径(具有单位权重边缘)。鉴于DFS可以深入研究,因此可以用尽所有选择,例如发现非循环图中两个节点之间的最长路径。 DFS还可用于图形中的周期检测。

最后,如果我们具有无限的深度和无限的分支因子,则可以使用迭代加深搜索(IDS)。

答案 12 :(得分:0)

这是一个很好的例子,可以证明在某些情况下BFS优于DFS。 https://leetcode.com/problems/01-matrix/

如果正确实施,两个解决方案都应该访问距离比当前单元格+1更远的单元格。 但是DFS效率低下并且反复访问同一个单元,导致O(n * n)复杂度。

例如,

1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
0,0,0,0,0,0,0,0,

答案 13 :(得分:0)

我认为这取决于您面临的问题。

  1. 简单图形上的最短路径-> bfs
  2. 所有可能的结果-> dfs
  3. 在图上搜索(处理树,martix也作为图)-> dfs ....