我试图用C ++编写图形类,作为邻接列表实现。我试图使这个类成为一个模板,以便节点和边可以包含任意有效负载。这是一个简单的想法,但我对语言如何支持这一点感到困惑。
我希望能够如下声明图表:
graph<int, int>
或
graph<string,double>
et.c.
第一个想法,从图表声明向后工作:
template<class ntype, class etype>
class node {
class edge {
etype payload;
node<ntype, etype>* to;
node<ntype, etype>* from;
}
ntype payload;
vector< edge<> > incoming; // How to avoid recursion ???
vector< edge<> > outgoing; // ????
}
template<class ntype, class etype>
class graph {
vector< node<ntype, etype> > nodes;
}
我对所涉及的递归,模板参数的范围等感到非常困惑。我已经尝试过查看嵌套类,typename与模板,其他问题,但它并没有让它更清晰。看起来C和void指针是现在编码的绝对最佳方式。非常感谢任何帮助或参考。
答案 0 :(得分:2)
我首先要在节点类之外声明边缘类。在这种情况下,我没有看到使它成为嵌套类的优势。实际上,嵌套类通常会带来比专业人士更多的缺点。 This问题对原因有很好的解释。
至于图表类的设计,我建议使用一个模板参数来表示有效负载(您可能希望图形节点携带的任意数据类型),第二个表示权重(任何数值) ,例如int
,float
,double
,long
等。
某些图形用例可能并不关心图形是否加权,因此在这些情况下你可以忽略权重字段,而不使用它(将它保留为某个默认值,如0,将是一个好的做法)。我还建议使用std::list
而不是std::vector
来保存节点,以便在您需要向图表中添加许多节点时,不会发生内存重新分配。
考虑到上述情况,图表类看起来如下所示。注意我对数据字段(有效负载)使用D
,对权重字段使用W
。
<强> DirectedGraph.h 强>
template <class D, class W> class DirectedGraph{
public:
DirectedGraph(){/*...*/}
~DirectedGraph(){/*...*/}
/*Pushes a node into this graph, which will have no connections initially.*/
void push(GraphNode<D, W> *node){/*...*/}
/*Erases a node from this graph.*/
void erase(GraphNode<D, W> *node){/*...*/}
std::list<GraphNode<D, W>> &getNodes(){/*...*/}
private:
/*This is the master list holding all nodes of this graph.*/
std::list<GraphNode<D, W>> nodes;
};
节点和边缘(我称之为&#39; Neighbor)类看起来像这样:
<强> GraphNode.h 强>
/*Forward declaration of the edge structure (see below).*/
template <class D, class W> struct Neighbor;
template <class D, class W> struct GraphNode{
public:
GraphNode(D data) : data(data) {}
~GraphNode(){}
/*Some data this node element will hold*/
D data;
/*Adds an outgoing connection.*/
void addConnection(Neighbor<D, W> neighbor){ /*...*/}
/*You may also want to develop a 'removeConnectoin' method here.*/
/*...*/
/*Nodes that this one is connected to. Since this actually represents
a connection (an edge), the struct 'Neighbor' is used, which encapsulates
a pointer to a 'GraphNode' as well as the weight of the edge.*/
std::list<Neighbor<D, W>> neighbors;
/*Nodes that connect to this one. These are the incoming connections. Note
that this is not of type 'Neighbor' because it does not represente an edge.
It is just a record of which nodes have an outgoing connection to this one.*/
std::list<GraphNode<D, W>*> parents;
};
/*This struct represents an edge*/
template <class D, class W> struct Neighbor{
Neighbor<D, W>(GraphNode<D, W> *node, W weight) : node(node), weight(weight){}
GraphNode<D, W> *node;
W weight;
};
这里要注意的一件事是使用Neighbor类的唯一原因是我们可以表示边的权重。如果您要使用的图表始终未加权,则只需替换std::list
Neighbor<D, W>
std::list
GraphNode<D, W>*
。您还可以从实现中删除模板参数W
。
哦,当然图表头文件必须包含节点一。
我希望这是一个很好的起点。有任何问题,请告诉我。