用C ++设计地图

时间:2011-12-29 07:35:04

标签: c++ algorithm dictionary data-structures shortest-path

我正在处理shortest path problem,这意味着我必须创建一个数据类型或类来模拟我的map。为了做到这一点,我现在使用map<string, map<string, int>>,其中第一个string是节点的名称(称为节点A),第二个参数是A连接到它们的节点的映射。到A.的距离。

虽然这很有效,但我觉得处理节点是一种相当麻烦的方式,创建地图比实际算法更耗时。任何人都可以建议在C ++数据结构中优雅地表达this之类的东西吗?

对不起,澄清一下。首先,这两种语法都是可管理的,但是如果有人可以建议更优雅的东西,那么欢迎,迭代地图是非常令人沮丧的,因为我还必须在较大的地图上迭代每个对中的“子地图”。其次,我测量了创建10个节点的映射的时间,并将其与实际算法运行所花费的时间进行了比较,创建然后运行需要更长的时间。

1 个答案:

答案 0 :(得分:4)

一个非常简单的方法是......一张桌子。

    +---+---+--
    | A | B |
+---+---+---+--
| A | 0 |100|
+---+---+---+--
| B |100| 0 |
+---+---+---+--

这可以相当简单地实现,然后你需要设计一种方法来表示没有连接,这可以通过使用sentinel值来完成。

其次,表示节点的方式不够充分。字符串是重量级的野兽。我建议创建一个从真实姓名到简单数字的映射,然后只使用表格中的数字。

例如,您可以使用这样的方法:

class Graph {
public:
  Graph() {}

  void addEdge(std::string const& left,
               std::string const& right,
               unsigned weight)
  {
    unsigned const leftIndex = this->getNode(left);
    unsigned const rightIndex = this->getNode(right);

    if (_graph.size() <= leftIndex) {
      _graph.resize(leftIndex + 1, Sentinel);
    }

    std::vector<unsigned>& leftEdges = _graph[leftIndex];
    if (leftEdges.size() <= rightIndex) {
      leftEdges.resize(rightIndex + 1, Sentinel);
    }

    unsigned& edge = leftEdges[rightIndex];
    if (edge != Sentinel) {
      std::cerr << "There was already a weight for '"
                << left << "' -> '" << right "'\n";
    } else {
      edge = weight;
    }
  }

  // Returns (weight, true) if the edge exists and (0u, false) otherwise
  std::pair<unsigned,bool> getWeight(std::string const& left,
                                     std::string const& right) const
  {
    unsigned const leftIndex = this->getNode(left);
    unsigned const rightIndex = this->getNode(right);

    try {
      unsigned const weight = _graph.at(leftIndex).at(rightIndex);
      return weight == Sentinel ? std::make_pair(0u, false) :
                                  std::make_pair(weight, true);
    } catch(std::out_of_range const&) {
      return std::make_pair(0u, false);
    }
  }

private:
  static unsigned const Sentinel = (unsigned)-1;

  unsigned getNode(std::string const& node) const {
    std::map<std::string, unsigned>::const_iterator it = _nodes.find(node);
    return it == _nodes.end() ? _graph.size() : it->second;
  }

  unsigned getNode(std::string const& node) {
    return _nodes.insert(std::make_pair(node, _nodes.size()));
  }

  std::map<std::string, unsigned> _nodes;
  std::vector< std::vector<unsigned> > _graph;
};

当然,如果您直接编码节点并且只处理积分(这将从类中删除所有这些字符串 - >无符号转换)会更简单。

另请注意,我为有向图创建了一个类,如果图不是定向的,则必须在以下选项之间进行选择:

  • 表示两个边缘(A - > B和B - > A)
  • 仅表示单个边缘,例如,仅表示(A - > B),您可以任意选择仅表示从较低指数到较高指数的边缘,例如