首先,我想澄清一点,我对图论和解析有向图的正确算法的经验很少,而且我在这里搜索了SO,但却找不到我想要的东西。希望你们能帮助我:)。
我有一个大的有向图(大约3000个节点),它有几个由连接节点组成的子图,子图不相互连接。这是我在这里的数据的一个小代表图:
我正在编写一个Perl脚本来查找从每个源节点到sink节点的所有可能路径,并将它们存储在一个数组数组中。因此,对于此图,可能的路径是:
1,2,3,4,5,6
1,2,3,4,5,7
1,8,9,10
11,12,13
11,14
15,16,17
我在脚本中完成此搜索的方式是在以下步骤中使用Graph模块:
以下是我的脚本中的一部分:
#Getting all source nodes in the graph:
my @source_nodes = $dot_graph->source_vertices();
my @sink_nodes = $dot_graph->sink_vertices();
# Getting all possible paths between from source to sink nodes in the graph:
print "Calculating all possible overlaps in graph\n";
my $all_possible_paths = $dot_graph->APSP_Floyd_Warshall();
print "Done\n";
# print "Extending overlapping contigs\n";
my @all_paths;
foreach my $source (@source_nodes) {
foreach my $sink (@sink_nodes) {
my @path_vertices = $all_possible_paths->path_vertices($source, $sink);
my $path_length = $all_possible_paths->path_length($source,$sink);
#Saving only the paths that actually exist:
push (@all_paths, \@path_vertices) unless (!@path_vertices);
}
}
问题在于它适用于小图形,但是现在我有3000个节点,它需要很长时间才能完成(假设每个路径需要1ms才能找到,需要312.5通过他们所有的日子)。我知道使用Floyd-Warshall算法找到图中所有可能的路径,只找到源和接收器之间的路径效率不高,但是当我编写脚本时,我需要尽快得到结果,而且我的图形要小得多。
我的问题是如何找到从图中每个源开始的所有路径,这些路径将以汇聚节点结束,而不首先找到所有可能的路径?这就是所谓的广度 - 第一次还是深度优先搜索?如何使用Perl实现(如果可能的话,使用Graph模块)?任何帮助都会很棒!
PS:为了让程序运行得更快,我开始尝试将初始大图分解为子图并运行原始脚本,但是使用{{3分叉搜索源和汇之间路径的主循环}}。你们怎么看待这种方法?
答案 0 :(得分:3)
你对找到最短路径不感兴趣,所以忘记所有那些最短路径算法。
您有兴趣找到所有路径。这称为树遍历,可以先执行深度优先或广度优先。由于您遍历整个树,因此采用哪种方法并不重要。以下内容使用递归执行深度优先搜索:
sub build_paths {
my ($graph) = @_;
my @paths;
local *_helper = sub {
my $v = $_[-1];
my @successors = $graph->successors($v);
if (@successors) {
_helper(@_, $_)
for @successors;
} else {
push @paths, [ @_ ];
}
};
_helper($_)
for $graph->source_vertices();
return \@paths;
}
die if $graph->has_a_cycle;
my $paths = build_paths($graph);
是的,可以将作品并行化,但我不是为你写的。
最让我担心的是记忆。根据路径中的分支数量,您可能很容易因内存不足而停止运行。请注意,将路径存储为字符串(逗号分隔值)将比将它们存储为数组所需的内存更少。