今天我很好看看我的STL选项。然后我想到了什么。
似乎链表(std :: list)的用途有限。也就是说,它只是看起来真的 如果
有用我的容器中元素的连续顺序很重要,
我需要在中间删除或插入元素。
也就是说,如果我只是想要大量数据并且不关心它的顺序,那么如果我想要O(log n)查找或者a,我最好使用std :: set(平衡树) std :: unordered_map(哈希映射)如果我想要O(1)期望的查找或std :: vector(一个连续的数组)以获得更好的引用局部性,或者std :: deque(一个双端队列)如果我需要插入前面和后面。
OTOH,如果顺序很重要,我最好使用std :: vector来获得更好的引用位置,减少开销或者std :: deque如果需要进行大量的调整。
那么,我错过了什么吗?或者链接列表不是很好吗?除了中间插入/擦除之外,为什么有人想要使用它?
答案 0 :(得分:11)
任何类型的插入/删除都是O(1)。即使std :: vector对于追加也不是O(1),它接近O(1)因为它大部分时间都是,但有时候你将不得不增长那个数组。
它也非常擅长处理批量插入,删除。如果你有100万条记录并希望从另一个列表(concat)中追加100万条记录,那就是O(1)。每个其他结构(假设stadard / naive实现)至少为O(n)(其中n是添加的元素数)。
答案 1 :(得分:2)
订单很常见。如果是,链表是好的。如果您有一个不断增长的集合,您可以选择链接列表,数组列表(C ++中的vector
)和双端队列(deque
)。如果要在列表中的任何位置修改(添加,删除)元素,请使用链接列表。如果快速检索很重要,请使用数组列表。如果要在数据结构的两端添加内容并使用快速检索很重要,请使用双端队列。对于deque
vs vector
问题:使用vector
,除非从头开始插入/删除内容非常重要,在这种情况下请使用deque
。有关详细信息,请参阅here。
如果订单不重要,链接列表通常不是理想的。
答案 2 :(得分:1)
std::list
以其splice()
方法而着称,它允许您在固定时间内将一个或多个元素从一个列表移动到另一个列表,而无需复制或分配任何元素或列表节点。
答案 3 :(得分:0)
这个问题让我想起了this infamous one。阅读它以了解为什么这些简单的数据结构很重要。
答案 4 :(得分:0)
链接列表是一种基本数据结构。其他数据结构(如哈希映射)可以在内部使用链表。
对于查找,两种不同的算法可能具有O(1)时间复杂度,但这并不意味着它们具有相同的性能。例如,第一个可能比第二个快10或100倍。
每当您需要存储,迭代并使用大量数据执行某些操作时,该任务的普通(和快速)数据结构就是链接列表。更复杂的数据结构适用于特殊情况,例如,当您不需要重复值时, Set 是合适的。
答案 5 :(得分:0)
std :: list具有以下属性:
这些属性中std :: vector没有(Back Seuqence)
虽然std :: set不支持任何序列属性或(反向容器)
那是什么意思呢? 后向序列是否支持rend()和rbegin()等的O(1)
有关完整信息,请参阅:
What are the complexity guarantees of the standard containers?
答案 6 :(得分:-1)
链接列表是不可变的和递归的数据结构,而数组是可变的和命令式的(=基于变化的)。在函数式编程中,通常没有数组 - 您不需要更改元素,而是将列表转换为新列表。虽然链接列表在这里甚至不需要额外的内存,但这对于数组来说是不可能有效的。
您可以轻松构建或分解列表,而无需更改任何值。
double [] = []
double (head:rest) = (2 * head):(double rest)
在C ++中,这是一种命令式语言,你不会经常使用list
。一个例子可以是游戏中的太空船列表,您可以从中轻松移除自上一帧以来已被摧毁的所有太空飞船。