我想实现一个表示抽象数据类型"cover of a set"的数据结构。集合的元素由整数索引表示,子集也是如此。每个元素uint64_t e
被分配给至少一个但可能是多个子集uint64_t s
。这可以通过将子集索引存储在std::vector
中来实现。任何元素将分配到的子集数通常远小于元素总数。
性能(时间和内存)很重要,您建议实施哪些?
std::vector<std::vector<uint64_t>>
std::vector<std::unordered_set<uint64_t>>
std::vector<std::set<uint64_t>>
频繁的操作包括:
答案 0 :(得分:1)
您可以尝试阅读Matt Austern的论文Segmented Iterators and Hierarchial Algorithms。他讨论了如何有效地处理container<container<T>>
形式的层次结构数据结构。需要解决的一个问题是迭代,好像你有一个单位container<T>
。为此,标准库算法需要专门用于所谓的分段迭代器。
分段迭代器是一个两级数据结构 - 从执行顶级迭代开始 - 还包含一个更深层次的局部迭代器。因为这些局部迭代器本身也可以是分段迭代器,这允许任意嵌套的数据结构(例如树和图)。
离散集的集合封面可以构造为std::vector<std::set<T>>
。将STL算法应用于这样的容器要么麻烦,要么需要分段迭代器和分层算法。不幸的是,标准库和Boost都没有实现这一点,所以你有一些工作要做。
答案 1 :(得分:1)
最快的是一对数据结构:
std::vector< std::unordered_set<X> > set_to_elements;
std::unordered_map< X, std::unordered_set<std::size_t> > element_to_sets;
两者保持连贯。 boost
多索引容器可能能够更有效地执行此双向导航。
将元素分配给子集
set_to_elements[subset].insert(element);
element_to_sets[element].insert( subset );
从子集中删除元素(并可能将其移动到另一个子集)
set_to_elements[subset].erase(element);
element_to_sets[element].erase( subset );
检查元素是否是特定子集的成员
return set_to_elements[subset].find(element) != set_to_elements[subset].end();
或 return element_to_sets [element] .find(subset)!= element_to_sets [element] .end(); 获取元素所属的所有子集
return element_to_sets[element];
对特定子集的所有元素进行有效迭代会很好,但我认为这与其他目标冲突
return set_to_elements[subset];
所有操作都是恒定时间和线性记忆。内存和时间要求大约是紧凑型内存和时间要求的两倍。
缓存[]
操作结果的微优化应该在实际代码中完成,如果它实际上对性能敏感的话。将迭代器从一个容器存储到另一个容器,以使操作#1和#2更快,是可选的,并且可以使它们更快地触摸,但我不会打扰。