数据结构——对图中重连通分量输出的释疑

关于图的关节点及重连通分量的一些概念,此处不再冗述,不理解的可以阅读相关资料:

 

http://www.cnblogs.com/bless/archive/2008/09/28/1256875.html

 

此处着重讲到,在算法DfnLow增加一些语句, 可把连通图的边划分到各重连通分量中。

 

上文中求重连通分量的代码如下:

 

void Graph::Biconnected ( ) { //公有函数:从顶点0开始深度优先搜索 
  

   int num = 1//访问计数器num 
 dfn = new int[NumVertices]; //dfn是深度优先数 
 low = new int[NumVertices]; //low是最小祖先号 
 for ( int i = 0; i < NumVertices; i++ ) { 
           dfn[i] 
= low[i] = 0
   } 

   DfnLow ( 0-1 ); //从顶点 0 开始
 delete [ ] dfn; 
   delete [ ] low;

 


}

 

 

void Graph::Biconnected ( const int u, const int v ) {
//私有函数:计算dfn与low, 根据其重连通分量输出Graph的边。
//在产生的生成树中, v 是 u 的双亲结点, S 是一个初始为空的栈,
//应声明为图的数据成员。

 

 

 int x, y, w; 
 dfn[u] 
= low[u] = num++
 w 
= GetFirstNeighbor (u); //找顶点u的第一个邻接顶点w 
 while ( w != - 1 ) { 
                          if ( v != w && dfn[w] < dfn[u] ) 
                                 S.Push ( (u,w) ); 
//w不是u的双亲且w先于u被访问, (u,w)进栈 
                      if ( dfn[w] == 0 ) { //未访问过, w是u的孩子 
                            Biconnected (w, u); //从w递归深度优先访问 
                            low[u] = min2 ( low[u], low[w] ); //根据先求出的low[w], 调整low[u]
                            if ( low[w] >= dfn[u] ) { //无回边, 原来的重连通分量结束 
                              cout << “新重连通分量: ” << endl; 
                                      do { 
                                           (x, y) 
= S.Pop ( );
                                           cout 
<< x << "," << y << endl; 
                                      } 
while ( (x, y) 与 (u, w) 不是同一条边 );
                                   }  
//输出该重连通分量的各边 
                       }  else if ( w != v ) //有回边,计算 

                                   low[u] = min2 ( low[u], dfn[w] ); //根据回边另一顶点w调整low[u]
                       w = GetNextNeighbor (u, w); //找顶点u的邻接顶点w的下一个邻接顶点

 }

 

 

文中提到,如果不是根的话,u成为关节点的充要条件就是至少有一个子女w  low[w]>=dfn[u],而low的求解又与其所有子女的low相关,所以,此处基本策略是递归,父节点的low的值随着所有子女的low值做调整。

 

上述有求重连通分量的这么一段话:

 

 

 if ( low[w] >= dfn[u] ) { //无回边, 原来的重连通分量结束 
    cout << “新重连通分量: ” << endl; 
                    do { 
                         (x, y) 
= S.Pop ( );
                         cout 
<< x << "," << y << endl; 
                    } 
while ( (x, y) 与 (u, w) 不是同一条边 );
  }
//输出该重连通分量的各边 

 

 

 这段话表明目前来说,u是关节点了,下面就把所有w下面的边都输出来,直到把(u,w)也输出来,这个构成 一个重连通分量。

 

这些边是什么时候被压入栈的呢?

 

 

if ( v != w && dfn[w] < dfn[u] ) 
              S.Push ( (u,w) ); 
//w不是u的双亲且w先于u被访问, (u,w)进栈 

 

这句话的判断条件一开始一直没怎么理解,后来才明白,其实这句话把所有的边都保存了,判断条件只是为了防止保存重复的边。

 

首先来看 v!=w,其实作为u的父亲,v其实也是u的邻居之一,但是(v,u)已经存在了,所以,没有必要把(u,v)也放进去。(对于无向图来说,两者其实一回事)。

 

其次再来看dfn[w]<dfn[u],

 

一种情况是w还未被访问过,则dfn[w]肯定等于0,成立。至于注释写到“//w不是u的双亲且w先于u被访问, (u,w)进栈 “,我估计是因为求low值都是先求子女,再求父亲,所以说是w先于u被访问,

 

这个判断的另外一层意思,很可能w是u的某个子孙q的子女,这样,(w,u)肯定已经作为回边被保存过了,这里dfn[w]>dfn[u],就不再需要保存了。


 

 

 

 

 

 

你可能感兴趣的:(数据结构,算法,delete,Graph)