在C ++的书中,我一直在阅读STL容器,特别是有关STL及其容器的部分。现在,我确实了解它们中的每一个都有它们自己的特定属性,并且我几乎要记住它们的所有属性……但是我还不了解的是,在每种情况下都使用它们。
有什么解释?首选示例代码。
在C ++的书中,我一直在阅读STL容器,特别是有关STL及其容器的部分。现在,我确实了解它们中的每一个都有它们自己的特定属性,并且我几乎要记住它们的所有属性……但是我还不了解的是,在每种情况下都使用它们。
有什么解释?首选示例代码。
Answers:
vector
空。stackoverflow.com/questions/10699265/...
unordered_map
,您有和unordered_set
(及其多变体)不在流程图中,但是当您不关心订单而是需要按键查找元素时,它们是不错的选择。他们的查找通常是O(1)而不是O(log n)。
这是一个流程图,其灵感来自于我创建的David Moore的版本(请参见上文),该版本是新标准(C ++ 11)的最新(大部分)。这仅是我个人的看法,这并不是不争的事实,但是我认为这对于本次讨论可能是有价值的:
vector (sorted)
与其他图表有点不一致。它不是不同类型的容器,只是相同std::vector
但已排序。更重要的是,我不明白为什么不能使用a std::set
进行有序迭代,如果那是迭代集合的标准行为。当然,如果答案是关于有序访问容器槽的值的话[]
,那么好的,您只能使用soted来做到std::vector
。但无论哪种情况,都应在“需要订单”问题之后做出决定
简单的答案:std::vector
除非您有真正的理由,否则请使用所有内容。
当您发现自己在考虑“ Gee,std::vector
由于X不能在这里很好地工作”的情况时,请以X为基础。
std::remove_if
几乎总是优于“迭代时删除”方法。
查看Scott Meyers撰写的有效STL。很好地解释了如何使用STL。
如果要存储确定数量/不确定数量的对象,并且永远不会删除任何对象,那么向量就是您想要的。它是C数组的默认替换,它的工作原理类似于一个,但不会溢出。您也可以使用reserve()预先设置其大小。
如果要存储数量不确定的对象,但是要添加并删除它们,则可能需要一个列表...因为可以删除元素而不移动任何后续元素-与vector不同。但是,它比向量占用更多的内存,并且您无法顺序访问元素。
如果您要使用一堆元素并仅查找那些元素的唯一值,则将它们全部读取到一个集合中即可完成此操作,并且也会对它们进行排序。
如果您有很多键/值对,并且想按键对它们进行排序,则映射很有用...但是每个键只包含一个值。如果每个键需要多个值,则可以在列表中使用向量/列表作为值,或者使用多图。
它不在STL中,而是在STL的TR1更新中:如果您有很多要通过键查找的键值对,而您不在乎它们的顺序,则可能想要使用哈希-tr1 :: unordered_map。我在Visual C ++ 7.1中使用了它,它被称为stdext :: hash_map。它具有O(1)的查找,而不是map的O(log n)的查找。
hash_map
实施不是很好。希望他们的表现更好unordered_map
。
list
功能。那里有明显的错误。
这完全取决于您要存储的内容以及要对容器执行的操作。以下是一些我最常使用的容器类示例(非常不详尽):
vector
:紧凑的布局,每个包含的对象几乎没有内存开销。高效地迭代。附加,插入和擦除操作可能很昂贵,尤其是对于复杂的对象。便宜地通过索引查找包含的对象,例如myVector [10]。在C中使用数组的地方使用。在许多简单对象(例如int)的地方使用Good。reserve()
在向容器添加很多对象之前,请不要忘记使用。
list
:每个包含的对象的内存开销较小。高效地迭代。附加,插入和擦除很便宜。使用您在C中使用链表的位置。
set
(和multiset
):每个包含的对象的显着内存开销。使用您需要快速找出该容器是否包含给定对象或有效合并容器的位置。
map
(和multimap
):每个包含的对象的显着内存开销。使用要存储键值对并快速按键查找值的位置。
zdan建议的备忘单上的流程图提供了更详尽的指导。
我学到的一个教训是:尝试将其包装在一个类中,因为一天更改容器类型可能会带来很多惊喜。
class CollectionOfFoo {
Collection<Foo*> foos;
.. delegate methods specifically
}
当您想中断有人在此结构上执行x的操作时,它不会花很多时间,并且节省了调试时间。
为工作选择理想的数据结构:
每个数据结构都提供一些操作,这些操作可能会改变时间复杂度:
O(1),O(lg N),O(N)等
本质上,您必须做出最大的猜测,即最应该执行哪些操作,并使用具有该操作的数据结构为O(1)。
很简单,不是吗(-:
auto myIterator = whateverCollection.begin(); // <-- immune to changes of container type
typedef Collection<Foo*> CollectionOfFoo;
就足够了?
我扩展了Mikael Persson出色的流程图。我添加了一些容器类别,数组容器和一些注释。如果您想要自己的副本,这里是Google绘图。谢谢,Mikael做基础! C ++容器选择器
我在另一个问题中回答了这个问题,该问题被标记为该问题的重复项。但是我觉得很高兴参考一些有关选择标准容器的决定的好文章。
正如@David Thornley回答的那样,如果没有其他特殊需要,std :: vector是必经之路。这是C ++的创建者Bjarne Stroustrup在2014年博客中提供的建议。
这是文章https://isocpp.org/blog/2014/06/stroustrup-lists的链接
并引用其中的内容
而且,是的,我的建议是默认使用std :: vector。
在评论中,用户@NathanOliver还提供了另一个不错的博客,该博客具有更具体的度量。https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html。