图的BFS和DFS学习笔记

来源:互联网 发布:3322域名更新 编辑:程序博客网 时间:2024/05/29 12:49
  研究一个图,很重要的一个问题便是图的遍历,该问题最简单的描述便是从连通图的一个结点出发,按照一定的顺序经过图的每一个结点,使得每个结点只经过一次,并且在经过结点时对该结点进行一定的操作,当图中所有的结点都被访问过后,遍历结束(当图不是连通的时候,遍历图则需要从不同连接块中各自选择一个结点进行遍历)。
  而我们在该问题中所关注的是遍历的顺序以及遍历中的操作。寻找这个顺序,我们可以解决一些比如寻找两结点间的一条路径等问题;而设计遍历中的操作,我们可以找到遍历的顺序以及解决一些比如两点间的最短路径等问题。
  图的遍历包含两个算法,分别是BFS(Breadth-first-search宽度优先搜索)和DFS(Depth-first-search深度优先搜索)。两种方法的实质都是把图缩减成一棵以开始搜索结点为根的树(或森林)。而正因为树的特点,使得遍历有序,而有序的特点则是很多问题解决的基础。下面对两种算法具体讨论:
BFS:
  简单地说就是先访问某点,然后访问该点的邻接点,接着在访问这些邻接点的邻接点,直到没有邻接点可以访问为止。BFS是分层的算法,即距离起点相同距离的结点为一层,而遍历是一层访问完再访问下一层
  具体算法为从某点s开始BFS,将s标记为已遍历,然后对s点进行某种操作,然后依次BFS所有与s相邻的结点。用数组visited(i)来记录第i个点是否已经被访问。BFS不好用递归表示,而不用递归需要借助队列来实现:
Procedure BFS(G):
  for all v in V:
    visited(v)=false
  for all v in V:
    initial a queue Q=empty
    visited(v)=ture
    function(v)
    push v to Q
    while q is not empty:
      pop the first vertex v' from Q
      for all u that is adjencent to v':
        if not visited(u):
          visited(u)=true
          function(u)
          push u to Q

DFS:
  简单地说就是先访问某点,然后从该点出发沿着某条路一直访问到底,接着从该点沿着另一条路一直访问到底,直到最后没有从该点出发的路为止。
  具体算法为从某点s开始DFS,将s标记为已遍历,然后对s点进行某种操作,然后依次DFS所有与s相邻的结点。用数组visited(i)来记录第i个点是否已经被访问。
用递归的实现:
Procedure DFS(G):
  for all v in V:
    visited(v)=false
  for all v in V:
    if not visited(v):
      visited(v)=true
      function(v)
      previsit(v)
      for all v' that is adjencent to v:
        DFS(v')
      postvisit(v)
不用递归则需要借助栈来实现:
Procedure DFS(G):
  for all v in V:
    visited(v)=false
  for all v in V:
    initial a stack S=empty
    visited(v)=true
    previsit(v)
    function(v)
    push v to S
    while S is not empty:
      v'=stack.top
      if there is no u that is adjecent to v' or that is adjecent to v' but not has been visited:
        pop the first vertex v' from S
        postvisit(v')
      else for all u that is adjencent to v':
        visited(u)=true
        function(u)
        push u to S

  下面则简单证明这两个算法的正确性:即BFS和DFS能遍历完所有从起始结点v出发可达的任意结点。
  用反证法证明,如果存在可达点u没有被访问,选择任意一条路径从v到u,以及该路上最后一个被访问的结点z和该路上z后面所相连的第一个结点w。无论采用哪种算法,这当到达点z的时候都会检测到相邻的w点,并且移到w点对其进行操作。所以总会存在一条路径使得w可达,而这与假设矛盾。(更严谨的应该用数学归纳法证明)
  接下来我们讨论如何设计对每个结点的操作来找到我们遍历的顺序,即从起始点到所给点的一条路径。我们可以用一个数组x[i]来记录到达第i个结点的上一个结点,当我们访问某个结点时,将产生该点的前一个点记录在数组就好,然后我们可以用回溯的方法找到该路径。
  BFS和DFS最重要的性质是遍历是有序的,结合该性质,以及我们巧妙地设计访问每个点时的具体操作,我们可以解决很多实际问题。
0 0
原创粉丝点击