我需要一个已排序和索引的容器。我想基于std:set或std :: vector构建它。通过使用set,我需要昂贵的std :: distance来计算其元素的索引。通过使用向量,我知道添加或删除元素是昂贵的。假设我的元素是一个指针(小对象)。我知道两个操作的复杂性是相同的。但哪一个更快?感谢。
答案 0 :(得分:3)
如果您需要一个支持排序顺序和按索引查找的数据结构,那么您一定要查看 order statistic tree ,这是一个专门用于支持这些操作的数据结构。它支持O(log n)时间中的插入和删除,O(log n)时间内元素索引的查找,以及O(log n)时间内按值或索引查找,因此它应该比矢量或集合接近。
不幸的是,STL没有构建它的订单统计树,因此您必须搜索第三方库(this earlier question and answer provides an example of one)。也就是说,您应该从订单统计树中获得的加速应该值得投资。
希望这有帮助!
答案 1 :(得分:2)
根据你们的建议,我把它测量为底部代码(添加了flat_set)。调试版本的结果是
for set:4.720976s wall,4.711230s user + 0.000000s system = 4.711230s CPU(99.8%) (也测试了set :: insert,花费的时间很少)
for vector:1.407571s wall,1.404009s user + 0.000000s system = 1.404009s CPU(99.7%)
for flat_set:0.327714s wall,0.327602s user + 0.000000s system = 0.327602s CPU(100.0%)
发布版本(我需要写出结果让编译器优化不要过度使用我的代码)给每个加速大约10倍。
我的结论是矢量快2-3倍,而boost flat_set是最好的。并且对于少于几百个(例如200个)的条目数,flat_set insert不比std :: set(没有w / o索引计算)慢。
int N = 10000;
{
boost::timer::auto_cpu_timer t;
std::set<int> s;
for (int i = 0; i < N; ++i)
{
auto it = s.insert(i);
int index = std::distance(s.begin(), it.first);
}
}
{
boost::timer::auto_cpu_timer t;
std::vector<int> v;
for (int i = 0; i < N; ++i)
{
v.insert(v.begin(), i);
}
}
{
boost::timer::auto_cpu_timer t;
boost::container::flat_set<int> s;
for (int i = 0; i < N; ++i)
{
auto it = s.insert(-i); // negative sign is used to make insertion
// (at the beginning) expensive
int index = std::distance(s.begin(), it.first);
}
}
答案 2 :(得分:0)
分隔存储和索引:
有一个整数向量{I},用于索引对象类型{T}的存储向量。
{I}通过它在{T}中指向的对象之间的比较进行排序。 插入/删除{I}比{T}更便宜。
每当向{T}向量添加新项时,都会将其索引插入到已排序的{I}中。
当你删除一个项目时,删除{I}中的索引,但你可以保持{T}中的对象不受影响,只需将刚刚删除的索引推回到重用向量{I'}。下次添加新项目时,可以在{I'}中弹出__并重新使用存储。
如果您知道所使用的项目数,可以在启动时调用{T}上的resize()以避免在运行时(重新)分配。
此方法与使用指针向量类似,优点是动态分配较少,缓存更友好,因为对象存储位于连续内存中。