【问题标题】:"inverse" associative container?“逆”关联容器?
【发布时间】:2012-09-19 00:25:36
【问题描述】:

在 stl 或一般情况下是否存在一种“反向”关联容器? 例如,我想要一个容器,其中相同的元素由一组键共享。

假设我的密钥是int,那么例如:

container.at(3) -> some object A
container.at(4) -> same object A
container.at(1) -> other object B

对于不同的操作,这个容器(理想情况下)具有与 std::map 相同的复杂性。这样的事情可能吗?

我最初考虑使用std::map<int, T*>,其中几个索引指向同一个对象,但是当从地图中删除一个项目时,运行时间在 O(n) 中,因为你必须检查其他项目看是否需要删除T object

在 stl 或 boost 中是否已经“本地”存在这种容器?

编辑: 一些使用示例:

container<int, myClass> myContainer;
myClass obj(...); //new object
myContainer.insert(3, obj); //insert object for specific key
myContainer.insert(2, obj); //insert same object for specific key, since both objects would compare equal we would actually not "insert" a new object but have it shared by both keys
myContainer.duplicate_object(2,5); //key 5 also has the same object as key 2 (and 3)
myContainer.getAllKeys(2); //would return 2,3 and 5 since they all reference the same object as key 2
myContainer.removeKey(3);
myContainer.removeKey(2);
myContainer.removeKey(5); //would destroy the object here, not before

【问题讨论】:

  • 我不明白这个问题。您的标题使用“反向”一词,您的问题使用“反向”一词。无论哪种方式,您的示例仍然没有阐明您的意思。你能举例说明如何使用这样的容器吗?假设存在 reverse_container 或 inverse_container 并编写一个 main() 方法来说明其工作原理。
  • 此外,某种计数器仍可让您在 O(1) 时间内删除。每次添加对象时计数器都会递增,每次删除时计数器都会递减。当计数达到零时,您可以将其删除。 (当然,这可能意味着扩展或包装 std::map。)
  • @ Code-Guru :关于拥有一个计数器:对于地图中的所有指针,您仍然必须在某处存储一个容器,说明该指针由 n 个键使用。因此,当您必须为给定指针递减计数器时,我看不出它怎么可能是 O(1)
  • std::map&lt;int, boost::shared_ptr&lt;T&gt;&gt; 呢?

标签: c++ stl std


【解决方案1】:

你可以用一个

std::map<int,std::shared_ptr<myclass>>

在作为标准一部分的 C++11 中。否则使用 Boost 库提供的共享指针。

共享指针的想法是它在内部保持一个引用计数,即它跟踪指针复制的次数。当您删除映射条目时,共享指针对象的析构函数将确保计数器递减。一旦达到零,该对象将被删除。


(编辑:)为了让答案更完整,几个用法示例:

#include <map>
#include <memory>

struct myclass
{

};


int main()
{
  std::map<int,std::shared_ptr<myclass>> mymap;

  /* std::make_shared() calls the constructor and creates a shared_ptr: */
  std::shared_ptr<myclass> object1 { std::make_shared<myclass>() };
  std::shared_ptr<myclass> object2 { std::make_shared<myclass>() };
  std::shared_ptr<myclass> object3 { std::make_shared<myclass>() };

  mymap[1] = object1;
  mymap[2] = object2;
  mymap[3] = object3;
  mymap[4] = object2;
  mymap[5] = object1;

  mymap.erase(2); // erases the (2,object2) entry
                  // therefore, decreases the counter
                  // for object2
                  // but (4,object2) is still intact

  return 0;
}

【讨论】:

  • 顺便提一下,推荐使用 boost ptr_map 等而不是 shared_ptrs 容器。
  • @RealzSlaw 有趣;我没有使用ptr_map 的经验,但如果有一些建议的理由,它可能有理由发布单独的答案。无论如何感谢您的评论。
  • 您的答案之间的区别仅在于性能。 AFAIK,它在功能方面是等效的。
【解决方案2】:

你可能想看看Boost.MultiIndex;描述说:

Boost 多索引容器库提供了一个类模板 命名为 multi_index_container,它可以构建 容器维护一个或多个具有不同排序的索引和 访问语义。

【讨论】:

  • 标题听起来像是他想要的,但他给出的示例听起来好像他只是想将轻量级对象作为值。
【解决方案3】:

因此,您既需要像 std::map 中那样快速插入和查找,还需要按值快速删除条目的能力。

没有标准的容器可以做到这一点。但是当你想自己写一个时,你可以通过维护两个内部数据结构来做到这一点:

  1. std::map 将键映射到值
  2. 第二个 std::multimap 将值映射到指向它们的键集

当你想按值删除键时,你可以在第二个地图中查找它。

【讨论】:

    猜你喜欢
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    • 2012-06-03
    相关资源
    最近更新 更多