图论——读书笔记(基于BFS广度优先算法的广度优先树)

广度优先树

 

对于一个图G=(V,E)在跑过BFS算法的过程中会创建一棵广度优先树。

形式化一点的表示该广度 优先树的形成过程是这样的:

对于图G=(V,E)是有向图或是无向图, 和图中的源结点s,

我们定义图G的前驱子图为Gf={Vf, Ef}。

其中Vf = {v ->V : v.f <>NIL} AND {s},

 Ef = {(v.f , v) : v->(Vf - {s})}

即,G的前驱子图Gf是这样定义的:

Gf中的点集合Vf  中的点是G中的前驱(父结点)结点不为空的 AND G图的源结点。

前驱子图Gf中的边集合Ef 中的边是不包括s(G图中的源点)的Gf图中的所有点v到 v的前驱结点v.f所构成的边。

 

如果前驱子图中的相应点集合Vf满足由从源结点s可以到达的结点组成,

并且对于所有的v->Vf,

子图Gf包含一条从源结点s到结点v的唯一简单路径,

且该路径也是图G里面从源结点s到结点v之间的一条最短路径的话,

那么前驱子图Gf就是广度优先树。

 

广度优先树实质是一棵连通的树,

并且|Ef| = |Vf| -1(即,边数= 图中结点总数-1)

 

下面所示的伪代码实现的了打印出从源结点s到结点v的一条最短路径上的所有的结点。

这里假定BFS已经计算出一棵广度优先树了。

 1 PRINT-PATH(G, s, v)
 2 
 3 if  v==s
 4     print s
 5 
 6 else if  v.f == NIL
 7     print "no path from " s "to" v "exists"
 8 
 9 elsePRINT-PATH(G, s, v.f)
10     print v

因为每次递归调用的时候,路径都比前一次调用中的路径少了一个结点,

所以该过程的运行时间是关于所输出路径上顶点数的一个线性函数。

 

下面是使用C++语言实现的PRINT-PATH的代码片段,

以及在生成广度优先树之后所实现的打印出s到结点v的一条最短路径上的所有结点。

 

大致的思想是这样的:

对图G跑一边BFS算法之后,

会根据BFS算法对每个结点的访问的顺序,

对G->Adj[i].father这一个属性进行按照BFS算法的特点进行赋值,

在赋值过后调用print_path这个方法就可以显示出来

源结点s到某一个结点v如果二者是相连通的话,

则会显示出二者之间通过广度优先遍历

所得到的连通路径上所经过的结点

void print_path(Graph *G, int s, int v)
{
      if(s == v)
        print("%c   ", G->Adj[s].name); 


      else if(G->Adj[v].father == NULL)
      
 printf("no path from  %c to %c\n", G->Adj[s].name, G->Adj[v].name );

     else  
    {
      print_path(G, s, G->Adj[v].father);   
       printf("%c   ", G->Adj[v].name);
    }
}

对图G跑过一边BFS算法之后,

Vf = {v ->V : v.f <>NIL} AND {s},

Ef = {(v.f , v) : v->(Vf - {s})}

所构成的数据结构是基于图G的广度优先树。

 

主要内容出自

《算法导论 第三版》

转载于:https://www.cnblogs.com/inuyasha1027/p/algorithm_BFS_Graph.html

你可能感兴趣的:(图论——读书笔记(基于BFS广度优先算法的广度优先树))