为什么深度优先搜索声称空间效率高?

时间:2013-12-06 16:52:41

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

在我正在学习的算法课程中,据说深度优先搜索(DFS)比广度优先搜索(BFS)更具空间效率。

为什么?

虽然他们基本上做同样的事情,但是在DFS中我们正在堆叠当前节点的后继者,而在BFS中我们将后续者列入其中。

3 个答案:

答案 0 :(得分:56)

您的困惑源于这样一个事实,即您显然假设可以通过将LIFO堆栈替换为FIFO队列来从BFS算法获得DFS算法。

这是一种流行的误解 - 根本不是这样。通过用堆栈替换BFS队列无法获得经典的DFS算法。这些算法之间的差异更为显着。

如果您采用BFS算法并简单地将FIFO队列替换为LIFO堆栈,您将获得可称为伪DFS 算法的内容。这种伪DFS算法确实会正确地再现DFS顶点前向遍历序列,但它不具有DFS空间效率,并且它不支持DFS反向遍历(回溯)。

同时,真正的经典DFS无法通过这种天真的队列到堆栈替换从BFS获得。经典的DFS是一种完全不同的算法,核心结构明显不同。 True DFS是一种真正的递归算法,它使用堆栈进行回溯目的,而不是用于存储顶点发现“front”(如BFS中的情况)。最直接的结果是在DFS算法中,最大堆栈深度等于DFS遍历中距原点顶点的最大距离。在BFS算法中(如前面提到的伪DFS),最大队列大小等于最大顶点发现前沿的宽度。

说明DFS和BFS(以及伪DFS)之间峰值内存消耗差异的最突出和极端的例子是星图:由大量数据包围的单个中心顶点(例如{{1外围顶点,每个外围顶点通过边连接到中心顶点。如果使用中心顶点作为原点在此图上运行BFS,则队列大小将立即跳转到1000。如果使用伪DFS(即如果只是用堆栈替换队列),显然会发生同样的事情。但是经典的DFS算法需要只有1000(!)的堆栈深度才能遍历整个图形。看到不同? 11000。这就是DFS更好的空间效率的意思。

基本上,请阅读任何关于算法的书籍,找到经典DFS的描述并查看它是如何工作的。您会注意到BFS和DFS之间的差异远远大于仅仅是队列与堆栈。

P.S。还应该说,可以构建一个图表的示例,该图表在BFS下具有较小的峰值内存消耗。因此,有关DFS更好的空间效率的声明应被视为可能“平均”应用于某些隐含的“漂亮”图形类别。

答案 1 :(得分:7)

在DFS中,在完全平衡的树上只需要线性到深度O(log(n))的空间,而BFS(广度优先搜索)需要O(n)(树的最宽部分是最低深度,在二叉树中有n / 2个节点)。

示例:

               1
              / \  
             /   \  
            /     \ 
           /       \
          /         \  
         /           \  
        /             \ 
       /               \
       2               2 
      / \             / \ 
     /   \           /   \  
    /     \         /     \  
   /       \       /       \  
   3       3       3       3
  / \     / \     / \     / \ 
 /   \   /   \   /   \   /   \  
 4   4   4   4   4   4   4   4
/ \ / \ / \ / \ / \ / \ / \ / \ 
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 

DFS需要空间:4
BFS需要在倒数第二行空间8

如果分支因子更高,情况会变得更糟

答案 2 :(得分:3)

在DFS中,使用的空间是O(h),其中h是树的高度。

在BFS中,使用的空间是O(w),其中w是树的“宽度”。

在典型的二叉树(即随机二叉树)中,w = Omega(n)和h = O(sqrt(n))。

在平衡树中,w = Omega(n)和h = O(log n)。