目录

深度优先搜索 Depth First Search

Algorithm Notes

Mark Chen | 12 Apr 2021

你使用哪种语言?我们会根据你选择的语言显示对应的代码示例

Python
Java

前置条件

在学习这个知识点前,你应该先学习……

深度优先算法

搜索实际上可以看作遍历图的所有节点,直到遇到目标节点为止的过程。深度优先搜索在遍历的过程中遵循这样的规则:

在所有待遍历的节点中,最深的节点最先被探索

这里的“深”指的是节点到开始探索的节点的距离(边的数量)。注意:与广度优先算法不同的地方在于深度优先算法不能保证找到的目标节点是最浅(最优)的

深度优先算法的实现

与 BFS 不同,在 DFS 中我们要维护一个 queue 来作为 Fringe 存储待探索的节点。


def depthFirstSearch(initialState, getSuccessor, getValidActions):
    """
    :param initialState: The Initial State of problem (sometimes the 'current state')
    :param getSuccessor: The State Transition Function that return the successors given the current state and action
    :param getValidActions: A function that takes current state and return a list of valid actions under current state
    """
    fringe = queue()    # The only difference between BFS and DFS
    exploredStates = set()
    
    # Add the Initial State into the Fringe before Searching Actually Start.
    fringe.push(initialState)
    while len(fringe) > 0:
		currState = fringe.pop()
        exploredState.add(currState)
            
        # Do Something Here
        
        for action in getValidActions(currState):
            # Add Successor States into the fringe
            successor = getSuccessor(currState, action)
            if successor not in exploredStates: fringe.push(successor)


Not Implemented Yet. See Python Version.

深度优先算法的复杂度

时间复杂度

深度优先算法的时间复杂度与广度优先算法的时间复杂度相同 - 是 $O(E + V)$,具体的解释和广度优先搜索的基本一致(使用 双向链表deque 实现的 queue 在取出节点时的时间复杂度也是 $O(1)$),所以直接 quote 过来。

假设我们要在图 $G(V, E)$ (图 $G$ 有 $V$ 个节点,$E$ 条边)上使用广度优先算法进行遍历,算法最多只会遍历所有节点1次(不会出现重复查看的情况),如果 Fringe 的 Stack 是用双头链表 deque 实现的,那么每次从 Fringe 中取出节点的时间复杂度是 $O(1)$。这总共贡献了 $O(V)$ 的时间复杂度。因为每一条边只会在一端的节点被探索到时被查看一次,所以边最多被探索 $2E$ 次。每次探索一条边(因为是从 dictionary 中取出)只会有 $O(1)$ 的时间复杂度,所以探索边的总时间复杂度是 $O(2E) = O(E)$。

综上所述,BFS 的时间复杂度是 $O(V + E)$

空间复杂度

假设我们在图 $G$ 上运行DFS,在 $G$ 中平均每个节点有 $\alpha$ 个子节点,目标节点在第 $n$ 层,那么当探索到目标节点时,算法的空间复杂度应该是 $Space(\alpha, n) = n \times (\alpha - 1)$,也就是 $O(n\alpha)$。

注意到这个空间复杂度比 BFS 的 $O(\alpha^n)$ 要好非常多倍,我们在已知目标节点深度较深或者图的 $\alpha$ 值较大时应该优先选择 DFS。

练习


评论区