我在最后做的是:
- 问题是找到两个节点之间长度为N的所有路径。 排除循环。
- 将数据读入作为边列表,例如来自->到节点的一对(假定节点名称是唯一的)
- 创建一个哈希表(或在boost和stl, c++中无序_map)作为值的节点名称作为键的哈希表。
- 第二个哈希表将包含第一个节点导致的所有节点作为键。
例如:
A->B
A->C
B->D
C->E
E->D
在将所有数据作为“边列表”读入后,保存输入数据的Perl表示形式的结果数据结构如下:
my %hash = (
'A' => {'B' => 1, 'C' => 1},
'B' => {'D' => 1},
'C' => {'E' => 1},
'E' => {'D' => 1},
);
判断一对节点是否直接连接可以通过以下方式(使用Perl)进行粗略计算:
sub search {
my ($from,$to) = @_;
if( $to eq '*' ){ return defined($x=$hash{$from}) ? [keys $hash{$from}] : [] }
return defined($x=$hash{$from}) && defined($x{$to}) ? [$to] : []
}
在上述函数中,通过将$to设置为'*',提供了返回所有与“from”节点连接的节点的功能。返回值是一个节点数组引用,这些节点直接连接到$from参数。
查找两个节点之间的路径需要递归使用上述函数。
例如:
sub path {
my ($from,$to, $hops, $save_results) = @_;
if( $hops < 0 ){ return 0 }
$results = search($from, '*');
if( "".@$results == 0 ){ return 0 }
$found = 0;
foreach $result (@$results){
$a_node = new Tree::Nary($result);
if( path($result, $to, $hops-1, $a_node) == 1 ){
$save_results->insert($save_results, -1, $a_node);
$found = 1;
}
}
return $found;
}
如果深度不太大(即 $hops < 6 ?),使用递归是可以的,因为会出现堆栈溢出 [sic]。
最棘手的部分是阅读结果并提取每个路径的节点。经过多次考虑,我决定使用 Tree::Nary(n元树)来存储结果。最终我们得到以下树形结构:
|-> B -> D
A -> |-> C -> E -> D
为了提取所有路径,请执行以下操作:
- 查找所有叶节点
- 从每个叶节点开始,通过其父节点向后移动到根节点并保存节点名称。
上述内容使用perl实现,但我也使用boost :: unordered_map进行哈希表的C ++实现。我还没有在C ++代码中添加树结构。
结果:对于3281415个边和18601个唯一节点,perl需要3分钟才能找到A ->'*'->'*'->B。准备好时,我会更新C ++代码。