我正在使用Boost Graph来尝试理解我在Graphviz Dot格式中生成的一些依赖图.
不幸的是,我对图理论知之甚少,所以我很难用图理论术语来构建我想知道的东西.
从具有〜150个顶点的有向依赖图中,我想在一个特定的顶点V上"放大",并构建一个包含V的子图,其所有传入边和它们的传入边,它的所有传出边和它们的传出边,有点像通过V的最长路径.
这些依赖图非常混乱,所以我想删除混乱,以便更清楚可能影响所讨论的顶点的内容.
例如,给定;
g
|
v
a -> b -> c -> d
| | |
v v |
e f <-------+
Run Code Online (Sandbox Code Playgroud)
如果我要运行算法c,我想我想要;
g
|
v
a -> b -> c -> d -> f
Run Code Online (Sandbox Code Playgroud)
不确定是否应该包括b - > f ...我认为它是因为所有顶点"之前"c应该包含它们的边缘,并且所有顶点"之后"c应该包括它们的外边缘,但是在我看来,这会失去一些信息.
感觉应该有一个算法来做到这一点(或者更明智的东西,不确定我是否想要做一些愚蠢的事情,参见上面的b-> f),但我不知道从哪里开始寻找.
谢谢!
Cal*_*602 41
好的,我将翻译并调整我的教程以适应您的具体问题.文档总是假定大量"使用命名空间"; 我不会使用任何你知道什么是什么.让我们开始 :
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/astar_search.hpp>
Run Code Online (Sandbox Code Playgroud)
首先,定义顶点和边缘:
struct Vertex{
string name; // or whatever, maybe nothing
};
struct Edge{
// nothing, probably. Or a weight, a distance, a direction, ...
};
Run Code Online (Sandbox Code Playgroud)
创建类型或图表:
typedef boost::adjacency_list< // adjacency_list is a template depending on :
boost::listS, // The container used for egdes : here, std::list.
boost::vecS, // The container used for vertices: here, std::vector.
boost::directedS, // directed or undirected edges ?.
Vertex, // The type that describes a Vertex.
Edge // The type that describes an Edge
> MyGraph;
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用Vertices和Edges的ID类型的快捷方式:
typedef MyGraph::vertex_descriptor VertexID;
typedef MyGraph::edge_descriptor EdgeID;
Run Code Online (Sandbox Code Playgroud)
实现你的图表:
MyGraph graph;
Run Code Online (Sandbox Code Playgroud)
阅读Graphviz数据,并提供图表:
for (each Vertex V){
VertexID vID = boost::add_vertex(graph); // vID is the index of a new Vertex
graph[vID].name = whatever;
}
Run Code Online (Sandbox Code Playgroud)
请注意,它graph[ a VertexID ]给出了一个顶点,但graph[ an EdgeID ]给出了一个边缘.以下是添加一个的方法:
EdgeID edge;
bool ok;
boost::tie(edge, ok) = boost::add_edge(u,v, graphe); // boost::add_edge gives a std::pair<EdgeID,bool>. It's complicated to write, so boost::tie does it for us.
if (ok) // make sure there wasn't any error (duplicates, maybe)
graph[edge].member = whatever you know about this edge
Run Code Online (Sandbox Code Playgroud)
所以现在你有了你的图表.你想获得顶点"c"的VertexID.为了简单起见,我们使用线性搜索:
MyGraph::vertex_iterator vertexIt, vertexEnd;
boost::tie(vertexIt, vertexEnd) = vertices(graph);
for (; vertexIt != vertexEnd; ++vertexIt){
VertexID vertexID = *vertexIt; // dereference vertexIt, get the ID
Vertex & vertex = graph[vertexID];
if (vertex.name == std::string("c")){} // Gotcha
}
Run Code Online (Sandbox Code Playgroud)
最后,获取顶点的邻居:
MyGraph::adjacency_iterator neighbourIt, neighbourEnd;
boost::tie(neighbourIt, neighbourEnd) = adjacent_vertices( vertexIdOfc, graph );
for(){you got it I guess}
Run Code Online (Sandbox Code Playgroud)
你也可以获得优势
std::pair<out_edge_iterator, out_edge_iterator> out_edges(vertex_descriptor u, const adjacency_list& g)
std::pair<in_edge_iterator, in_edge_iterator> in_edges(vertex_descriptor v, const adjacency_list& g)
// don't forget boost::tie !
Run Code Online (Sandbox Code Playgroud)
那么,对于你真正的问题:
in_edges的示例(从未编译或尝试过,从我的脑海中浮现):
void findParents(VertexID vID){
MyGraph::inv_adjacency_iterator parentIt, ParentEnd;
boost::tie(parentIt, ParentEnd) = inv_adjacent_vertices(vID, graph);
for(;parentIt != parentEnd); ++parentIt){
VertexID parentID = *parentIt;
Vertex & parent = graph[parentID];
add_edge_to_graphviz(vID, parentID); // or whatever
findParents(parentID);
}
}
Run Code Online (Sandbox Code Playgroud)
换句话说,只需将Parent重命名为Children,并使用adjacency_iterator/adjacent_vertices.
希望这可以帮助.
这是它最终的结果.我意识到我需要完全按照边缘和边缘工作:
// Graph-related types
typedef property < vertex_name_t, std::string > vertex_p;
typedef adjacency_list < vecS, vecS, bidirectionalS, vertex_p> graph_t;
typedef graph_t::vertex_descriptor vertex_t;
typedef std::set< graph_t::edge_descriptor > edge_set;
// Focussing algorithm
edge_set focus_on_vertex(graph_t& graph, const std::string& focus_vertex_name)
{
const vertex_t focus_vertex = find_vertex_named(graph, focus_vertex_name);
edge_set edges;
collect_in_edges(graph, focus_vertex, edges);
collect_out_edges(graph, focus_vertex, edges);
return edges;
}
// Helpers
void collect_in_edges(const graph_t& graph, vertex_t vertex, edge_set& accumulator)
{
typedef graph_t::in_edge_iterator edge_iterator;
edge_iterator begin, end;
boost::tie(begin, end) = in_edges(vertex, graph);
for (edge_iterator i = begin; i != end; ++i)
{
if (accumulator.find(*i) == accumulator.end())
{
accumulator.insert(*i);
collect_in_edges(graph, source(*i, graph), accumulator);
}
}
}
void collect_out_edges(const graph_t& graph, vertex_t vertex, edge_set& accumulator)
{
typedef graph_t::out_edge_iterator edge_iterator;
edge_iterator begin, end;
boost::tie(begin, end) = out_edges(vertex, graph);
for (edge_iterator i = begin; i != end; ++i)
{
if (accumulator.find(*i) == accumulator.end())
{
accumulator.insert(*i);
collect_out_edges(graph, target(*i, graph), accumulator);
}
}
}
vertex_t find_vertex_named(const graph_t& graph, const std::string& name)
{
graph_t::vertex_iterator begin, end;
boost::tie(begin, end) = vertices(graph);
for (graph_t::vertex_iterator i = begin; i != end; ++i)
{
if (get(vertex_name, graph, *i) == name)
return *i;
}
return -1;
}
Run Code Online (Sandbox Code Playgroud)
这也处理有问题的顶点之前或之后的循环.我的源依赖图有周期(颤抖).
我试图将collect _*_ edges一般化为模板化的collect_edges,但是我没有足够的元编程调试能量来花费它.
| 归档时间: |
|
| 查看次数: |
12317 次 |
| 最近记录: |