如何维护2个对象列表

时间:2010-04-22 21:01:41

标签: c++ stl

我的c ++程序需要维护2个对象列表。

list<A*> inuse;
list<A*> free;

所以对象A甚至可以在“使用中”列表或“免费”列表中,但不能同时在两者中 http://www.cplusplus.com/reference/stl/list/

我想使用'list'作为我的列表的数据结构。 我的问题是

  1. 为什么我不能随机访问列表中的elmenet,我看上面的api,我看不到有办法获得inuse[2];
  2. 如何删除列表中的元素?有一个erase(),但是如何使用它来删除元素#2?我删除元素2后? STL列表会自动填充删除的斑点吗?例如#3将成为#2,#4将成为#3,依此类推?
  3. 谢谢。

8 个答案:

答案 0 :(得分:7)

使用std::vector。 它具有随机元素访问权限([]at())。

//does NOT check for out of range
myvector[i];

//does check for out of range
myvactor.at(i);

您可以使用erase()从矢量中删除元素,它会自动处理漏洞(#3变为#2,依此类推)

//erase the 6th element
myvector.erase (myvector.begin()+5);

// erase the first 3 elements:
myvector.erase (myvector.begin(),myvector.begin()+3);

但是如果您需要逐个删除多个对象,并且列表中不能有2个相同的对象,则可以尝试使用std::map。使用object的一些唯一属性作为键,并将itselt对象作为值(或对象本身为键,true作为值)。它还具有类似的随机访问运算符[]erase()函数。

答案 1 :(得分:6)

遗憾的是,恒定时间删除和固定时间随机访问是互斥的。

使用线性时间std::list的{​​{1}}进行随机访问,或使用std::advance(我的推荐)或std::deque并接受线性时间删除。

如果你总是删除系列中的第二项,std::vector有可能保持不变的删除时间。 dequedeque类似,但分为与内容列表相关联的小块。

或者,如果您的数据已排序,请使用vector进行固定时间删除和日志(N)时间访问。

任何容器中删除项目由std::set完成。列表,矢量,双端队列,地图,等等。

答案 2 :(得分:6)

如果你需要快速访问和快速删除,请考虑std :: set,它应该同时具有logn查找和logn insert / delete,同时仍然被排序

答案 3 :(得分:0)

std::list是在名为doubly linked list的数据结构之后建模的。

  1. 您不能使用随机访问,因为对象位于堆上,指向其位置的指针存储在上一个和下一个元素中。在std :: vector中,内存是连续的,你可以通过对象的偏移*大小来访问第n个元素。

  2. 通过获取该对象的迭代器并使用该迭代器(或范围)调用std :: list :: erase来删除元素。 erase返回一个迭代器,该迭代器指向您刚删除的元素的下一个指针所指向的元素。

  3. 是的,该地点将自动填补。

  4. 所有人都说,如果有疑问,请使用std :: vector。

答案 4 :(得分:0)

std :: list是一个双向链表。这意味着您有一系列包含元素的节点,如此

a&lt; - &gt; b - &lt; - &gt; c - &lt; - &gt; d。

当你删除'b'时,会发生的事情是指针被调整,以便节点a指向节点c,b被删除,即

A&LT; - &GT;℃下; - &GT; d

没有[]运算符的原因是,如果要查找第5个元素,则需要按照指向第5个元素的链接。数据结构不支持快速访问特定位置。在数组或向量中,所有元素都是彼此相邻的,因此这是微不足道的。您只需将5 * sizeof(数据)添加到指向顶部的指针。

deque也允许快速访问,但快速插入和删除只能从正面或背面进行。

我怀疑你真正想要的是std :: set或std :: map,这样你就可以找到该元素并快速移动到另一个元素。

答案 5 :(得分:0)

list<>是一个相当差的名字;它实际上是一个链表。你想要vector<>(.Net的List<>和Java的ArrayList。)

答案 6 :(得分:0)

我在这里猜测很多......但是......

我认为您需要能够使用这两个列表执行不同的操作。听起来你正在编写某种池化分配器。

我希望,“免费列表”只需要让你从前面推出弹出;它是一个fifo堆栈,可用于存储当前未使用但可在需要分配且“空闲列表”当前不为空时使用的对象。

“活动列表”是所有当前分配的对象的列表。分配器可能需要能够报告这些,或者对它们做任何事情,或者其他什么。 “活动列表”要求您可以在取消分配对象时从任何位置删除对象。我猜它会被推到免费列表中重复使用。

现在,可用于每个“列表”的数据结构可能不同。这一切都取决于具体要求。如果我在所需的使用语义上是正确的,我会说你应该能够使用std::list<A *>作为你的“免费列表”。如果您不关心能够按分配顺序走“活动列表”,那么您可以使用std::set<A *>作为“活动列表”。为了避免需要在集合中执行查找以从“活动列表”中删除对象,您可以将迭代器存储到对象集合中对象的位置(除非对象本身从对象中移除,否则此迭代器不会失效)设置 - 或者说这个answer并且我没有检查它但是我确信有人会纠正我,如果我错了)。如果您需要能够按照分配顺序遍历“活动列表”,那么您可以使用std::map<size_t, A *>并将递增分配索引存储为映射键;再次'对象持有快速擦除的迭代器'技巧应该有效。

答案 7 :(得分:0)

我将“inuse”和“free”列表实现为双向链表,然后创建数组“inuse_pointers”和“free_pointers”来保存指向列表元素的指针。这样,您可以使用指针数组索引链接列表(并避免必须遍历列表),并将保持双向链接列表的快速插入/删除操作。这不是一种典型的STL方法(这是从我目前正在处理的一些C语言缓存管理代码中获取的)但我知道它有效且效率很高。