【问题标题】:C++ Template Graph Class, RecursionC++ 模板图类,递归
【发布时间】:2014-08-30 00:16:15
【问题描述】:

我正在尝试用 C++ 编写一个图形类,实现为邻接列表。我正在尝试使此类成为模板,以便节点和边可以包含任意有效负载。这是一个简单的想法,但我对语言如何支持这一点感到困惑。

我希望能够声明如下图:
graph<int, int>
graph<string,double>

第一个想法,从图形声明向后工作:

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;
}

我对所涉及的递归、模板参数的范围等感到非常困惑。我尝试过查看嵌套类、类型名与模板以及其他问题,但这并没有让它变得更清楚。现在看来,C 和 void 指针绝对是编写此代码的最佳方式。非常感谢任何帮助或参考。

【问题讨论】:

  • edge 不是模板,去掉尖括号。添加缺少的分号、调味和it compiles。似乎是什么问题?你觉得需要避免什么递归?
  • 谢谢@IgorTandetnik,你是对的。其他问题让我认为我必须使用某种嵌套模板声明。 IE。模板>或其他。

标签: c++ templates recursion graph


【解决方案1】:

我首先要在节点类之外声明边缘类。在这种情况下,我看不出将其设为嵌套类有什么好处。实际上,一般来说,嵌套类带来的弊大于利。 This 问题对原因有很好的解释。

至于图形类的设计,我建议使用一个模板参数来表示有效负载(您可能希望图形节点携带的任何任意数据类型),并使用第二个模板参数来表示权重(任何数值,如intfloatdoublelong等)。

某些图表用例可能不关心图表是否加权,因此在这些情况下,您可以忽略权重字段,并且不要使用它(将其保留为某个默认值,例如 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;

};

节点和边(我称之为“邻居”)类将如下所示:

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 类的唯一原因是我们可以表示边缘的权重。如果您要使用的图表始终未加权,您可以将Neighbor&lt;D, W&gt;std::list 替换为GraphNode&lt;D, W&gt;*std::list。您还可以从您的实现中删除模板参数W

哦,当然,图形头文件必须包含节点一。

我希望这是一个好的起点。有任何问题,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多