我正准备实现我自己的类以便从数组中有效删除,但我想我会问是否已经存在类似的东西。我想要的是类似列表的访问效率,但使用数组。我想使用数组是出于缓存一致性的原因,所以我不必一直调用内存分配器(因为在分配节点时使用std :: list)。
我想做的是创建一个包含两个数组的类。第一个是一组元素,第二个数组是一组整数,其中每个整数是第一个数组中的空闲槽。所以我可以相当容易地从数组中添加/删除元素,而无需为它们分配新的内存,只需从空闲列表中取一个索引并将其用于新元素。
这样的事情是否存在?如果我自己做,我还必须自己制作迭代器,这样你就可以迭代这个集合,避免数组中的任何空插槽,而且我不太喜欢它。
感谢。
注意:我想在集合上执行的操作类型是:
答案 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
可能对您有用。