双索引的最佳容器

时间:2008-09-18 17:37:16

标签: c++ stl containers

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

你会推荐什么?

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

3 个答案:

答案 0 :(得分:4)

我根据你的写作做了几个假设:

  • 按键复制和比较便宜
  • 系统中只应有一个对象副本
  • 相同的键可以引用许多对象,但只有一个对象对应于给定的键(一对多)
  • 您希望能够有效地查找哪些对象与给定键对应,以及哪个键对应于给定对象

我建议:

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

一种选择是使用两个引用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;
};

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