【问题标题】:Best container for double-indexing双索引的最佳容器
【发布时间】:2010-09-10 19:40:58
【问题描述】:

设置允许双索引的容器的最佳方法是什么(在 C++ 中)?具体来说,我有一个对象列表,每个对象都由一个键索引(每个键可能多个)。这意味着一个多图。然而,这样做的问题在于,它意味着查找对象位置的方法可能比线性查找更糟糕。我宁愿避免重复数据,所以让每个对象保持它自己的坐标并且必须在地图中移动自己会很糟糕(更不用说移动你自己的对象可能会在成员函数中间接调用你的析构函数!)。我宁愿一些容器通过对象指针和坐标维护索引,并且对象本身保证稳定的引用/指针。然后每个对象可以存储一个迭代器到索引(包括坐标),充分抽象,并知道它在哪里。 Boost.MultiIndex 似乎是最好的主意,但它非常可怕,我不希望我的实际对象需要是 const。

你会推荐什么?

编辑:Boost Bimap 看起来不错,但它提供稳定的索引吗?也就是说,如果我更改坐标,对其他元素的引用必须保持有效。我想使用指针进行索引的原因是因为对象没有内在顺序,并且指针可以在对象更改时保持不变(允许在 Boost MultiIndex 中使用它,IIRC 确实提供了稳定的索引)。

【问题讨论】:

  • 您的文章似乎可以互换使用“键”和“坐标”;你能澄清一下吗?您的应用程序是否需要键和对象之间的多对多关系,或者一个键可以引用多个对象但每个对象只有一个键?

标签: c++ stl containers


【解决方案1】:

我根据你的文章做了几个假设:

  • 复制和比较密钥的成本很低
  • 系统中应该只有一个对象的副本
  • 同一个键可以引用多个对象,但只有一个对象对应一个给定键(一对多)
  • 您希望能够有效地查找哪些对象对应于给定键,以及哪个键对应于给定对象

我建议:

  • 使用链表或其他容器来维护系统中所有对象的全局列表。对象在链表上分配。
  • 创建一个std::multimap<Key, Object *>,将键映射到对象指针,指向链表中的单个规范位置。
  • 执行以下操作之一:
    • 创建一个std::map<Object *, Key>,允许查找附加到特定对象的密钥。确保您的代码在更改密钥时更新此映射。 (如果您需要多对多关系,也可以是 std::multimap。)
    • 向包含当前KeyObject 添加一个成员变量(允许O(1) 查找)。确保您的代码在更改密钥时更新此变量。

由于您的文章提到“坐标”作为键,您可能也有兴趣阅读Fastest way to find if a 3D coordinate is already used 的建议。

【讨论】:

    【解决方案2】:

    很难理解你到底在用它做什么,但似乎 boost bimap 是你想要的。除了特定的用例之外,它基本上是提升多索引,并且更易于使用。它允许基于第一个元素或第二个元素进行快速查找。为什么要通过地址在地图中查找对象的位置?使用抽象并让它为您完成所有工作。请注意:对地图中所有元素的迭代是 O(N),因此可以保证 O(N)(不会更糟)以查找您正在考虑的方式。

    【讨论】:

      【解决方案3】:

      一种选择是使用两个引用 shared_ptrs 的 std::maps。这样的事情可能会让你继续前进:

      template<typename T, typename K1, typename K2>
      class MyBiMap
      {
      public:
          typedef boost::shared_ptr<T> ptr_type;
      
          void insert(const ptr_type& value, const K1& key1, const K2& key2)
          {
              _map1.insert(std::make_pair(key1, value));
              _map2.insert(std::make_pair(key2, value));
          }
      
          ptr_type find1(const K1& key)
          {
              std::map<K1, ptr_type >::const_iterator itr = _map1.find(key);
              if (itr == _map1.end())
                  throw std::exception("Unable to find key");
              return itr->second;
          }
      
          ptr_type find2(const K2& key)
          {
              std::map<K2, ptr_type >::const_iterator itr = _map2.find(key);
              if (itr == _map2.end())
                  throw std::exception("Unable to find key");
              return itr->second;
          }
      
      private:
          std::map<K1, ptr_type > _map1;
          std::map<K2, ptr_type > _map2;
      };
      

      编辑:我刚刚注意到多地图要求,这仍然表达了这个想法,所以我会离开它。

      【讨论】:

        猜你喜欢
        • 2013-03-28
        • 1970-01-01
        • 2022-01-22
        • 2014-05-13
        • 2021-02-07
        • 2020-06-21
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        相关资源
        最近更新 更多