Java 有一个LinkedHashSet,它是一个具有可预测迭代顺序的集合。C++ 中最接近的可用数据结构是什么?
目前我正在使用集合和向量来复制我的数据。我将我的数据插入到集合中。如果数据插入成功(意味着数据集中不存在),那么我 push_back 进入向量。当我遍历数据时,我使用向量。
Java 有一个LinkedHashSet,它是一个具有可预测迭代顺序的集合。C++ 中最接近的可用数据结构是什么?
目前我正在使用集合和向量来复制我的数据。我将我的数据插入到集合中。如果数据插入成功(意味着数据集中不存在),那么我 push_back 进入向量。当我遍历数据时,我使用向量。
如果可以使用它,那么带有和索引的Boost.MultiIndex与.sequenced
hashed_unique
LinkedHashSet
如果做不到这一点,请保留某种类型的unordered_set
(或者hash_set
,如果这是您的实现所提供的),其中包含一个列表节点,并使用该列表节点自己处理顺序。
您当前正在做的事情(set
和vector
)的问题是:
mutable
被顺序比较忽略的数据成员,并且有人编写的代码期望通过查找发生变异并看到更改时依次迭代)。LinkedHashSet
的是,没有快速的方法可以删除序列中间的元素。如果要按值而不是按位置删除,则必须在向量中搜索要删除的值。set
具有与散列集不同的性能特征。如果您不关心这些事情中的任何一个,那么您所拥有的可能就很好。如果重复是唯一的问题,那么您可以考虑保留指向集合中元素的指针向量,而不是重复向量。
LinkedHashSet
要在 C++ 中从 Java复制,我认为您将需要两个 vanilla std::map
(请注意,您将得到LinkedTreeSet
而不是真正的LinkedHashSet
,而不是得到 O(log n) 用于插入和删除)才能工作。
当您要插入时,您std::map::find
首先使用std::map
以确保其中不存在相同的对象。
std::map
我之前提到的两者。当您要按插入顺序遍历它时,您将遍历第二个std::map
,因为它将按插入顺序排序(任何属于std::map
or的std::set
内容都会自动排序)。
当您要从中删除一个元素时,您可以使用它std::map::find
来获取插入顺序。使用此插入顺序从第二个元素中删除元素std::map
并从第一个元素中删除对象。
请注意,此解决方案并不完美,如果您打算长期使用此解决方案,则需要在删除一定数量后“压缩”插入订单,因为您最终会用完插入订单(2 ^32 个索引用于 unsigned int 或 2^64 个索引用于 unsigned long long int)。为此,您需要将所有“值”对象放入向量中,清除两个映射中的所有值,然后将向量中的值重新插入两个映射。此过程需要 O(nlogn) 时间。
如果您使用的是 C++11,则可以将第一个替换为std::map
以std::unordered_map
提高效率,但您将无法用它替换第二个。原因是std::unordered map
使用哈希码进行索引,因此在这种情况下无法可靠地对索引进行排序。
您可能想知道 std::map 不会像“null”查找时间那样为您提供任何类型的 (log n)。并且使用 std::tr1::unordered 是有风险的业务,因为它会破坏任何排序以获得恒定的查找时间。
尝试 bash 一个 boost 多索引容器以更自由地使用它。
除了使用(相当于Java的HashSet)和(双向链表)之外,您描述组合的方式std::set
听起来std::vector
像您应该做的事情。您还可以使用将键(用于查找)与迭代器一起存储到列表中,以查找您存储的实际对象(如果键与对象不同(或仅其中一部分))。std::unordered_set
std::list
std::unordered_map
boost 库确实提供了许多此类容器和查找索引的组合。例如,这个具有快速查找示例的双向列表。