C++ 我应该在我的特殊情况下使用向量还是集合?还是完全不同的东西?

C++ 我应该在我的特殊情况下使用向量还是集合?还是完全不同的东西?,c++,sorting,boost,stl,containers,C++,Sorting,Boost,Stl,Containers,所以,我花了很多时间阅读各种各样的问题、博客文章、文章等,关于不同情况下不同STL容器的性能比较 然而,我还没有找到一个好的来源来说明我的确切情况(3D游戏): 我收集了大量指向某个类的指针(肯定超过5k,可能低于50k)(我认为其确切性质不相关),并希望通过单个浮点值对它们进行排序,该值确定它们到某个任意位置的距离(在帧中不会改变) 之后,我想迭代每个存储的指针。这里的顺序很重要,因此排序也很重要 以下是伪代码的情况: // A: Insertion foreach (class instan

所以,我花了很多时间阅读各种各样的问题、博客文章、文章等,关于不同情况下不同STL容器的性能比较

然而,我还没有找到一个好的来源来说明我的确切情况(3D游戏):

我收集了大量指向某个类的指针(肯定超过5k,可能低于50k)(我认为其确切性质不相关),并希望通过单个浮点值对它们进行排序,该值确定它们到某个任意位置的距离(在帧中不会改变)

之后,我想迭代每个存储的指针。这里的顺序很重要,因此排序也很重要

以下是伪代码的情况:

// A: Insertion
foreach (class instance that needs sorting):
    container.insert( pair(distanceOfInstance, instance) );

// B: Sorting - using the distanceOfInstance as the determining factor
container.sort();

// C: Iteration in sorted order
foreach (pair in container)
    doSomethingWith(pair.instance);
整个过程(可能)在游戏中的每一帧都会重复,所以这里的最佳性能相当重要。每次A之前必须清理容器。在C之后,对其不做任何其他操作

我不需要(重复,不需要)的:

  • 随机访问容器
  • 在容器排序后插入新元素的能力
目前,我认为最快的是使用向量或集合。但我不知道在我的情况下,将元素插入到向量中,然后对其排序,然后对每个元素迭代一次是否会更快。或者,将元素插入到一个集合中(从而在插入过程中对它们进行排序),然后在每个元素上迭代一次会更快


在我们的项目中,我们还将boost用于其他一些任务,所以如果有人知道boost内部的更好的解决方案(或者完全其他的),我非常乐意听取建议。另外,如果这个问题已经得到了回答,但我没有找到它,那么很抱歉:)

如果您只需要对元素进行一次排序,我认为如果使用vector,您将获得更好的性能。你也可以考虑使用一个列表,虽然我认为它会比向量稍微慢一些。p> 性能总是很棘手的:您应该以两种方式实现它,并衡量哪种方式可以提供更好的输出


也就是说,我认为vector是一个更好的选择,如果您在创建时保留了足够的元素:如果您使用set,则新插入的元素将在每次插入时排序到集合中。有了vector,你只会在同一时间产生这样的成本。

vector在实践中几乎总是更快;如果不需要将更新与查找交错,则没有理由使用

也就是说,你也可以看看谷歌的实现,它应该比set更快


1也就是说,除非您也在检查和删除重复项,有许多重复项。

(这并不常见。)

如其他答案所述,在您的情况下应使用向量。关于时间复杂度,对向量进行排序需要时间O(n logn),其中n是插入的元素数。对于
std::set
,已经排序的序列每插入一次都要付出O(logn)的代价。插入n个元素也会导致O(n logn)运行时间。但由于更好的内存局部性(简而言之,它存储在一个连续的内存范围内,可以快速读取和写入),向量解决方案将更快

此外,
std::vector
仅具有恒定的空间开销,而
std::set
具有线性开销(通常实现为)

如果您有很多次迭代,并且n是一个大数字,请避免在每次迭代中分配向量的内存。所以不是

while (true) {
  vector<YourClass*> container;
  container.reserve(numInstancesInCurrentIteration);
  // your code, insertions with 'container.emplace_back(...)'
}
while(true){
载体容器;
容器保留(NUMINSTANCESIncirentIteration);
//您的代码,插入“container.emplace_back(…)”
}
执行类似的操作:

vector<pair<float, YourClass*> > container;
while (true) {
  if (container.size() < numInstancesInCurrentIteration)
    container.resize(numInstances, pair<float, YourClass*>(-1.f, NULL));

  // A: Insert using assignments
  size_t pos = 0;
  foreach (class instance that needs sorting):  // pseudo-code
    container[pos++] = make_pair(distanceOfInstance, &instance);

  // B: Sort only the used range
  std::sort(container.begin(), container.begin() + pos);

  // C: Iterate over pointers sorted by distance
  for (auto it = container.begin(); it != container.begin() + pos; ++it)
    doSomethingWith(it->second);
}
向量容器;
while(true){
if(container.size()second);
}

经过一些迭代后,对
container.resize()
的调用将变得非常罕见。调用
doSomethingWith(YourClass*)
可能会成为程序中最昂贵的部分。

正如其他人回答的那样,我也会选择vector。它更简单,可以更多地访问对象的内存布局。

如何?否则,使用
std::set
不必进行排序,因为插入时会对值进行排序。另外,请记住,如果您事先知道(即在“A”点)要添加的项目数,您可以使用来消除
std::vector
所需的重新分配。这取决于需要更快的是什么:插入还是迭代?最好的选择是,同时尝试时间和现实的测试。你是否提前知道每次“通过”你将处理多少个项目?如果是这样,向量很可能是您的目标,保留大小,并在排序之前放置插入的对象(故意选择的单词)。sub 50k排序应该足够快,迭代显然是理想的。不管是哪种方式,您都需要对其进行测试。您可能还需要研究(和基准测试)其他方面(例如)。每个迭代中的元素数量是否相同?或者已知所有迭代的最大次数(您所说的可能低于50K)?如果是,只分配一次向量可以节省大量时间。如果是的话,我可以为你写一个示例代码。是的,我错过了不好的答案!这多少有些道理