我有一个(C ++)std::map<int, MyObject*>
,其中包含数千万个MyObject*
类型的对象。我可以拥有的最大对象数量约为1亿。关键是对象的id。在某个过程中,必须以某种方式标记这些对象(使用0
或1
)。标记不会发生在对象本身上(因此我不能引入成员变量并将其用于标记过程)。由于我知道最小和最大ID(1到100_000_000),我想到的第一个想法是使用std::bit_set<100000000>
并在那里执行我的标记。这解决了我的问题,并且在标记进程并行运行时也更容易,因为它们使用自己的bit_set来标记事物,但我想知道解决方案可能是什么,如果我不得不使用其他东西而不是{{1} } - 0
标记,例如,如果我必须使用整数标记所有对象,我可以使用什么?
是否有某种形式的数据结构能够以紧凑(内存方式)的方式处理这类问题,而且速度快?感兴趣的主要问题是对象是否被标记,以及标记的是什么。
谢谢。
注意:1
无法更改。无论我使用何种数据结构,都不得处理地图本身。
答案 0 :(得分:4)
如何将地图的value_type
改为std::pair<bool, MyObject*>
而不是MyObject*
?
答案 1 :(得分:3)
如果你不关心记忆,那么std::vector<int>
(或任何适合你的需要代替int
)应该有效。
如果您不喜欢这样,并且无法修改地图,那么为什么不为标记创建平行地图?
std::map<id,T> my_object_map;
std::map<id,int> my_marker_map;
如果无法直接修改对象,是否考虑在将对象放入地图之前将其包裹起来? e.g:
struct
{
int marker;
T *p_x;
} T_wrapper;
std::map<int,T_wrapper> my_map;
如果您无论如何都需要进行查找,那么这将不会更慢。
编辑:正如@tenfour在他/她的回答中所说, std::pair
可能是一个更清洁的解决方案,因为它保存了{{1} }定义。就个人而言,我不是struct
的忠实粉丝,因为你必须将所有内容称为std::pair
和first
,而不是通过有意义的名称。但那只是我......
答案 2 :(得分:1)
要问自己最重要的问题是“这些100,000,000个物体中有多少可能被标记(或保持未标记)?”如果答案小于大约100,000,000/(2*sizeof(int))
,则只需使用其他std::set
或std::tr1::unordered_set
(hash_set
之前的tr1
)来跟踪哪些内容如此标记(或者没有标记。)
2*sizeof(int)
来自哪里?它是在将要标记的项列表的双端队列中维护堆结构的内存开销量的估计值。
如果它更大,则使用您要使用的std::bitset
。对于您需要的数量规模,它的开销实际上是0%。你需要大约13兆的连续ram来保存bitset。
如果您需要存储标记和在线状态,请使用std::tr1::unordered_map
的密钥和Object*
的值使用marker_type
。同样,如果标记节点的百分比高于上述比较,那么您将需要使用某种bitset
来保持所需的位数,并进行适当的大小调整,每位12.5 MB
在澄清要求的情况下,持有bitset
的专用对象可能是您的最佳选择。
编辑:这假设您已经为可接受的解决方案做了适当的时间复杂度计算,因为不再允许更改基础std::map
结构。
答案 3 :(得分:0)
如果您不介意使用黑客攻击,请查看Boost.MultiIndex中使用的memory optimization。它可以在存储指针的LSB中存储一位。