我在进行有向图的广度优先搜索时,遇到了正确分类边的困难。
在进行广度优先或深度优先搜索期间,您可以将遇到的边分为4类:
- TREE(树边)
- BACK(返祖边)
- CROSS(横叉边)
- FORWARD(前向边)
Skiena [1] 给出了实现方法。如果您沿着从v1到v2的边移动,在Java中有一种方法可以返回DFS期间的边类型(用于参考)。parents map 返回当前搜索的父顶点,timeOf()
方法返回发现该顶点的时间。
if ( v1.equals( parents.get( v2 ) ) ) { return EdgeClass.TREE; }
if ( discovered.contains( v2 ) && !processed.contains( v2 ) ) { return EdgeClass.BACK; }
if ( processed.contains( v2 ) )
{
if ( timeOf( v1 ) < timeOf( v2 ) )
{
return EdgeClass.FORWARD;
}
else
{
return EdgeClass.CROSS;
}
}
return EdgeClass.UNCLASSIFIED;
我的问题是,我无法正确地执行有向图上的BFS(广度优先搜索)。例如:
以下循环图是可以的:
A -> B
A -> C
B -> C
BFS 从 A 开始,会先发现 B,然后是 C。边 eAB 和 eAC 是 TREE edges,在穿过 eBC 最后一次时,B 和 C 被处理并被发现,这条边被正确地分类为 CROSS。
但普通的循环不起作用:
A -> B
B -> C
C -> A
当最后穿过边eCA时,A被处理并被发现。因此,这条边被错误地标记为CROSS,而实际上它应该是一条BACK边。即使两条边具有不同的类别,处理这两种情况的方法确实没有区别。
如何在有向图上实现BFS的适当边分类?
[1] http://www.algorist.com/
编辑:
这里是从@redtuna答案中得出的实现。我只是添加了一个检查,以避免获取根节点的父节点。我有JUnits测试表明它适用于有向图和无向图,在循环、直线、分叉、标准示例、单个边等情况下...
@Override
public EdgeClass edgeClass( final V from, final V to )
{
if ( !discovered.contains( to ) ) { return EdgeClass.TREE; }
int toDepth = depths.get( to );
int fromDepth = depths.get( from );
V b = to;
while ( toDepth > 0 && fromDepth < toDepth )
{
b = parents.get( b );
toDepth = depths.get( b );
}
V a = from;
while ( fromDepth > 0 && toDepth < fromDepth )
{
a = parents.get( a );
fromDepth = depths.get( a );
}
if ( a.equals( b ) )
{
return EdgeClass.BACK;
}
else
{
return EdgeClass.CROSS;
}
}