索引集(用于向量中的有效删除)

时间:2013-05-20 10:25:17

标签: c++ arrays

我正准备实现我自己的类以便从数组中有效删除,但我想我会问是否已经存在类似的东西。我想要的是类似列表的访问效率,但使用数组。我想使用数组是出于缓存一致性的原因,所以我不必一直调用内存分配器(因为在分配节点时使用std :: list)。

我想做的是创建一个包含两个数组的类。第一个是一组元素,第二个数组是一组整数,其中每个整数是第一个数组中的空闲槽。所以我可以相当容易地从数组中添加/删除元素,而无需为它们分配新的内存,只需从空闲列表中取一个索引并将其用于新元素。

这样的事情是否存在?如果我自己做,我还必须自己制作迭代器,这样你就可以迭代这个集合,避免数组中的任何空插槽,而且我不太喜欢它。

感谢。

注意:我想在集合上执行的操作类型是:

  1. 迭代
  2. 通过索引(或我正在考虑的“句柄”)随机访问各个元素
  3. 删除集合中任意位置的元素
  4. 在集合中添加元素(顺序不重要)

4 个答案:

答案 0 :(得分:1)

如果维护元素的顺序无关紧要,请使用swap-and-pop。

将最后一个元素复制/移动到要删除的元素上,然后弹出后面的元素。超级简单高效。你甚至不需要特别检查去除元素,因为如果你使用标准的C ++向量和操作它就会工作(tm)。

*iter = std::move(container.back());
container.pop_back();

我不记得pop_back()是否使vector上的迭代器失效,但我认为不行。如果是这样,只需直接使用索引或重新计算新的有效迭代器。

auto delta = iter - container.begin();
// mutate container
iter = container.begin() + delta;

答案 1 :(得分:1)

std::list<T>实际上听起来与您工作的理论上正确的数据结构完全相同,因为它支持您列出的四个操作,所有操作都具有最佳的空间和时间复杂度。 std::list<T>::iterator是一个句柄,即使您在列表中添加/删除其他项目,它仍然有效。

可能有一个自定义分配器(即 std::allocator<T>)可以与std::list<T, Allocator>一起使用以获得所需的性能(内部池节点,然后每次添加或删除节点时都不要进行运行时分配。但这可能有点矫枉过正。

我会开始只使用带有默认分配器的std::list<T>,然后只查看自定义分配器或其他数据结构,如果您发现性能对您的应用程序来说太糟糕了。

答案 2 :(得分:1)

您可以通过在空插槽的空白处存储有关“空”插槽的信息来使用单个阵列。

对于数组A中的连续空插槽块,例如从索引k开始的n个插槽,将(k, n')存储在位置A[n](其中n'是下一个空闲索引块的索引。如果阵列存储字大小的对象,则可能必须将两个整数打包成一个单词。

你实际上存储了一个空闲块的链表,就像内存管理器一样。

代码有点痛苦,但是这将允许你在O(1)时间内分配一个自由索引,并在O(n)时间内迭代分配的索引,其中n是数字分配的插槽。在最坏的情况下,释放索引将是O(n)时间:这与碎片化内存的问题相同。

对于第一个空闲块,您可以单独存储索引,也可以使用您从未分配的约定A[0],这样您就可以始终从那里开始自由索引搜索。

答案 3 :(得分:0)

std::map可能对您有用。