我对c ++比较陌生,我正在尝试为特定问题选择最合适的数据结构,但我发现很难找到答案。
我希望创建一个小的(最多1000个elems)数组,包括整数或简单结构。在我的代码中,我将需要添加和删除数组中的元素,但我不希望一直动态地重新分配ram的开销。此外,因为我将有其他变量指向我的数组中的元素我不想重新编号/重新排序元素,因为这将搞砸这种关系。由于我可以确定我的数组中最大数量的元素,我很乐意预先分配所有必需的ram,但我不确定如何有效地跟踪哪些元素变为空闲,以便我可以重新使用它们作为新元素需要。这类问题有明显的数据结构吗? 提前谢谢。
答案 0 :(得分:3)
std:vector<>
似乎很符合您的要求:
vector::reserve()
为您为阵列规划的最大元素数量分配足够的存储空间 - 请注意reserve()
实际上并未向向量添加元素。向量仍将具有与调用reserve()
之前相同数量的元素。但是,它确保vector
在将元素添加到vector
时不需要执行重新分配,除非该附加元素会导致元素数量超过预留。这也意味着指向vector
的指针将保持稳定。答案 1 :(得分:2)
您正在寻找Pool allocator。您可以自己编写或使用Boost.Pool
答案 2 :(得分:2)
您所描述的基本上是固定大小的内存池。你没有解释为什么需要它。除非有特定的理由将对象保持在类似数组的结构中,否则您应该通过new
单独分配它们。您不需要池分配器,除非分析器说服您。
如果您确实有理由将所有对象保留在数组中,无论出于何种原因,您将实现自己的基于数组的池分配器。最简单的一个使用简单的链表来跟踪空闲块。保留第一个未使用元素的索引,每个未使用的元素保留下一个元素的索引。 除非你确切地知道自己在做什么以及为什么,否则你不应该这样做。
答案 3 :(得分:0)
我不希望一直动态重新分配ram的开销
您可以考虑使用vector<>
。它在需要时进行动态分配,但不是所有时间。它是高效编写的容器。
因为我可以确定我的数组中有最大数量的元素 很高兴预先分配所有必需的
在声明矢量时,您可以将大小指定为:
vector<int> vi(1000);
您也可以从其他地方参考vi
。
答案 4 :(得分:0)
std::vector 是您应该使用的&amp;使用智能指针代替原始指针。
答案 5 :(得分:0)
由于您仍希望维护外部变量和内部数组元素之间的关系,是的,您无法对它们进行重新排序。但是,当您删除/添加无法满足您需求的新元素时,使用std :: vector将重新排序其余元素。
您可以将bool值与数组中的每个元素组合,指定该元素是否正在使用中。请注意,如果内存对您至关重要,则可以使用位图。
struct CElement
{
// specify whether this element is in use
bool isUsed;
int element;
}
const size_t MAX_CAPACITY = 1000;
CElement myArray[MAX_CAPACITY];
另一种选择是使用链接列表。添加或删除链接列表中的节点需要恒定时间,而指向其他节点的指针仍保持不变。因此,您可以通过让外部变量保存指向节点而不是数组索引的指针来建立“关系”。此外,您甚至不需要提前预先分配1000个元素。
答案 6 :(得分:0)
我将补充一点,即分配整数/小结构的开销很小,如果你初始化一个没有元素的vector
而使用vector.push_back()
和vector.erase()
,那就意味着你不需要跟踪哪些元素是免费的,哪些元素不是。你似乎关注效率,但记得按照这个顺序做事:
答案 7 :(得分:0)
我认为在这种情况下最好的方法是使用预先分配的双向链表......
// Untested code... just to give the idea
struct Node
{
int data;
Node *prev, *next;
static Node *first, *last, *free;
// Allocates a new node before the specified node or
// at the end of the list if before is NULL
static Node *alloc(int data, Node *before)
{
// Check the free list first
Node *n = free;
if (!n)
{
// There are no free nodes... allocate a bunch of them
Node *page = new Node[1000];
for (int i=0; i<999; i++)
{
page[i].next = &page[i+1];
}
page[999].next = NULL;
n = free = &page[0];
}
// Update the free list
free = n->next;
// Link the new node to neighbors
n->next = before;
n->prev = before ? before->prev : last;
if (n->prev) n->prev->next = n; else first = n;
if (n->next) n->next->prev = n; else last = n;
// Initialize it
n->data = data;
return n;
}
// Deallocates a node, placing it in the free list for reuse
static dealloc(Node *n)
{
if (n)
{
// Remove from double chain
if (n->next) n->next->prev = n->prev; else last = n->prev;
if (n->prev) n->prev->next = n->next; else first = n->next;
// Add to free list
n->next = free; free = n;
}
}
};
当您需要分配节点时,只需调用Node::alloc
传递数据以及放置节点的位置。当你需要释放它时,只需调用node dealloc。
节点在“页面”中分配,并在重新分配后重用。这样可以最大限度地减少对内存管理器的调用次数,并且可以大大加快速度。
双向链接结构永远不需要在内存中移动现有节点(因此不需要调整指针)。重新排序元素也很容易,例如添加Node::moveTo(Node *before)
方法。
这种方法的缺点是,在给定索引的情况下访问第n个元素是O(n)操作。