deque和list STL容器有什么区别?

时间:2009-09-16 23:23:56

标签: c++ list stl deque

两者有什么区别?我的意思是方法都是一样的。因此,对于用户来说,他们的工作方式相同。

这是正确的吗?

9 个答案:

答案 0 :(得分:104)

让我列出差异:

  • Deque 使用a管理其元素 动态数组,提供随机 访问,并且几乎相同 接口作为矢量。
  • 列表将其元素管理为 双向链表并没有 提供随机访问

  • Deque 提供快速插入和删除功能 结束和开始。插入和删除元素 中间是相对缓慢的,因为 所有元素都可以达到两者之一 结束可以移动以腾出空间或者去 填补空白。
  • 列表中,每个位置的插入和删除元素都很快, 包括两端。

  • Deque :元素的任何插入或删除 除了在开始或结束 使所有指针,引用无效, 和引用元素的迭代器 deque。
  • 列表:插入和删除元素 不会使指针,引用无效, 和其他元素的迭代器。

<强>复杂性

             Insert/erase at the beginning       in middle        at the end

Deque:       Amortized constant                  Linear           Amortized constant
List:        Constant                            Constant         Constant

答案 1 :(得分:45)

来自SGI STLdeque摘要(日期但仍非常有用):

  

deque非常像一个向量:就像vector一样,它是一个支持随机访问元素的序列,在序列末尾不断插入和删除元素,以及线性时间插入和删除元素。中间。

     

deque与vector不同的主要方式是deque还支持在序列开头的常量时间插入和元素删除。另外,deque没有任何类似于vector的capacity()和reserve()的成员函数,也没有提供与这些成员函数相关的迭代器有效性的任何保证。

以下是来自同一网站的list摘要:

  

列表是双向链表。也就是说,它是一个支持前向和后向遍历的序列,以及(开始)(开始)常量时间插入和删除元素的开始或结束,或中间。列表具有重要的属性,即插入和拼接不会使列表元素的迭代器无效,甚至删除也只会使指向被删除元素的迭代器无效。可以更改迭代器的顺序(也就是说,list :: iterator在列表操作之后可能具有与之前不同的前导或后继),但迭代器本身不会失效或被指向不同的元素,除非该失效或突变是明确的。

总之,容器可能有共享例程,但这些例程的时间保证因容器而异。在考虑将哪些容器用于任务时,这一点非常重要:考虑到如何最常用的容器(例如,更多用于搜索而不是插入/删除)需要很长的路要走引导你到正确的容器。

答案 2 :(得分:7)

std::list基本上是一个双重链接列表。

另一方面,

std::deque更像是std::vector。它具有索引的持续访问时间,以及开头和结尾的插入和删除,这提供了与列表截然不同的性能特征。

答案 3 :(得分:4)

没有。 deque仅在前后支持O(1)插入和删除。例如,它可以在具有环绕的向量中实现。由于它也保证了O(1)随机访问,你可以确定它不使用(只是)一个双向链表。

答案 4 :(得分:3)

另一个重要保证是每个不同容器将其数据存储在内存中的方式:

  • 向量是单个连续的内存块。
  • deque是一组链接的内存块,每个内存块中存储多个元素。
  • 列表是分散在内存中的一组元素,即:每个内存“块”只存储一个元素。

请注意,deque旨在尝试平衡向量和列表的优点,而没有各自的缺点。它是内存受限平台中特别有趣的容器,例如微控制器。

内存存储策略经常被忽略,但是,它通常是为特定应用选择最合适容器的最重要原因之一。

答案 5 :(得分:2)

其他人已经很好地解释了性能差异。我只想补充一点,类似甚至相同的接口在面向对象编程中很常见 - 这是编写面向对象软件的一般方法的一部分。你不应该假设两个类的工作方式相同,只是因为它们实现了相同的接口,你应该假设一匹马像狗一样工作,因为它们都实现了attack()和make_noise()。

答案 6 :(得分:2)

dequelist之间的显着差异

  • 对于deque

    并排存储的项目;

    针对从两侧(正面,背面)添加数据进行了优化;

    以数字(整数)索引的元素。

    可以通过迭代器甚至通过元素的索引进行浏览。

    时间访问数据更快。

  • 对于list

    “随机”存储在内存中的项目;

    只能由迭代器浏览;

    针对中间的插入和移除进行了优化。

    由于数据的空间位置非常差,因此对数据的时间访问速度较慢,迭代速度很慢。

    处理非常大的元素

您还可以检查以下Link,它比较了两个STL容器(使用std :: vector)之间的性能

希望我分享了一些有用的信息。

答案 7 :(得分:2)

我为我的 C++ 课上的学生制作了插图。 这是(松散地)基于(我对)GCC STL 实现中的实现( https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_deque.hhttps://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_list.h)

双端队列

Illustration of std::deque

集合中的元素存储在内存块中。每个块的元素数量取决于元素的大小:元素越大,每个块越少。潜在的希望是,如果无论元素的类型如何,块的大小都相似,那么在大多数情况下这应该有助于分配器。

您有一个列出内存块的数组(在 GCC 实现中称为映射)。除了第一个可能在开头有空间和最后一个可能在结尾有空间之外,所有内存块都已满。地图本身从中心向外填充。与 std::vector 相反,这就是如何在恒定时间内完成两端的插入。与 std:::vector 类似,可以在恒定时间内进行随机访问,但需要两个间接访问而不是一个。与 std::vector 类似且与 std::list 相反,在中间删除或插入元素的成本很高,因为您必须重新组织大部分数据结构。

双向链表

Illustration of a std::list

双向链表可能更常见。每个元素都存储在自己的内存块中,独立于其他元素分配。在每个块中,您都有元素的值和两个指针:一个指向前一个元素,一个指向下一个元素。它使得在列表中的任何位置插入元素变得非常容易,甚至可以将元素的子链从一个列表移动到另一个列表(称为拼接的操作):您只需要更新位于插入点的开始和结束。缺点是要通过索引找到一个元素,您必须遍历指针链,因此随机访问在列表中的元素数量方面具有线性成本。

答案 8 :(得分:1)

这是列表,无序映射的概念验证代码使用,可提供O(1)查找和O(1)精确的LRU维护。需要(未擦除的)迭代器在擦除操作中生存下来。计划在O(1)任意大的软件托管的缓存中使用GPU内存上的CPU指针。向Linux O(1)调度程序点头(每个处理器的LRU <->运行队列)。通过哈希表,unordered_map具有恒定的访问时间。

message.delete()