deque 和 list STL 容器有什么区别?
两者有什么区别?我的意思是方法都是一样的。因此,对于用户来说,它们的工作原理是相同的。
这是正确的吗?
What is the difference between the two? I mean the methods are all the same. So, for a user, they work identically.
Is that correct??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
让我列出差异:
动态数组,提供随机
访问,并且几乎相同
接口作为向量。
双向链表并且不
提供随机访问。
结束和开始。插入和删除元素
中间相对较慢,因为
直到两者之一的所有元素
末端可以移动以腾出空间或
填补一个空白。
包括两端。
除了开头或结尾之外
使所有指针、引用无效,
和引用元素的迭代器
双端队列的。
不使指针、引用无效,
以及其他元素的迭代器。
复杂性
Let me list down the differences:
dynamic array, provides random
access, and has almost the same
interface as a vector.
doubly linked list and does not
provide random access.
both the end and the beginning. Inserting and deleting elements in
the middle is relatively slow because
all elements up to either of both
ends may be moved to make room or to
fill a gap.
including both ends.
other than at the beginning or end
invalidates all pointers, references,
and iterators that refer to elements
of the deque.
not invalidate pointers, references,
and iterators to other elements.
Complexity
来自(已过时但仍然非常有用)SGI STL
双端队列
:以下是来自同一站点的
list
的摘要:总之,容器可能具有共享例程,但是这些例程的时间保证因容器而异。当考虑使用这些容器中的哪一个来执行任务时,这一点非常重要:考虑容器的最频繁使用方式(例如,更多地用于搜索而不是插入/删除)会大有帮助引导您到正确的容器。
From the (dated but still very useful) SGI STL summary of
deque
:Here's the summary on
list
from the same site:In summary the containers may have shared routines but the time guarantees for those routines differ from container to container. This is very important when considering which of these containers to use for a task: taking into account how the container will be most frequently used (e.g., more for searching than for insertion/deletion) goes a long way in directing you to the right container.
std::list
基本上是一个双向链表。std::deque
,另一方面,其实现更像是std::vector
。它通过索引具有恒定的访问时间,以及在开头和结尾处的插入和删除,这提供了与列表截然不同的性能特征。std::list
is basically a doubly linked list.std::deque
, on the other hand, is implemented more likestd::vector
. It has constant access time by index, as well as insertion and removal at the beginning and end, which provides dramatically different performance characteristics than a list.我为 C++ 课上的学生制作了插图。
这是(松散地)基于(我的理解)GCC STL 实现中的实现(
https://github .com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_deque.h 和 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B% 2B-v3/include/bits/stl_list.h)
双端队列
集合中的元素存储在内存块中。每个块的元素数量取决于元素的大小:元素越大,每个块越少。潜在的希望是,如果无论元素的类型如何,块的大小都相似,那么大多数时候这应该对分配器有帮助。
您有一个列出内存块的数组(在 GCC 实现中称为映射)。所有内存块都已满,除了第一个内存块(可能在开头有空间)和最后一个内存块(可能在末尾有空间)。地图本身是从中心向外填充的。与 std::vector 相反,这就是可以在恒定时间内完成两端插入的方式。与 std:::vector 类似,可以在恒定时间内进行随机访问,但需要两个间接而不是一个。与
std::vector
类似,与std::list
相反,在中间删除或插入元素的成本很高,因为您必须重新组织大部分数据结构。双向链表
双向链表可能更为常见。每个元素都存储在自己的内存块中,独立于其他元素进行分配。在每个块中,您都有元素的值和两个指针:一个指向前一个元素,一个指向下一个元素。它使得在列表中的任何位置插入元素变得非常容易,甚至将元素的子链从一个列表移动到另一个列表(称为拼接的操作):您只需更新以下位置的指针:插入点的开头和结尾。缺点是要通过索引找到一个元素,您必须遍历指针链,因此随机访问在列表中的元素数量方面具有线性成本。
I've made illustrations for the students in my C++ class.
This is based (loosely) on (my understanding of) the implementation in the GCC STL implementation (
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_deque.h and https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_list.h)
Double-ended queue
Elements in the collection are stored in memory blocks. The number of elements per block depends on the size of the element: the bigger the elements, the fewer per block. The underlying hope is that if the blocks are of a similar size no matter the type of the elements, that should help the allocator most of the time.
You have an array (called a map in the GCC implementation) listing the memory blocks. All memory blocks are full except the first one which may have room at the beginning and the last which may have room at the end. The map itself is filled from the center outwards. This is how, contrarily to a
std::vector
, insertion at both ends can be done in constant time. Similarly to astd:::vector
, random access is possible in constant time, but requires two indirections instead of one. Similarly tostd::vector
and contrarily tostd::list
, removing or inserting elements in the middle is costly because you have to reorganize a large part of the datastructure.Doubly-linked list
Doubly-linked list are perhaps more usual. Every element is stored in its own memory block, allocated independently from the other elements. In each block, you have the element's value and two pointers: one to the previous element, one to the next element. It makes it very easy to insert element at any position in the list, or even to move a subchain of elements from one list to another (an operation called splicing): you just have to update the pointers at the beginning and end of the insertion point. The downside is that to find one element by its index, you have to walk the chain of pointers, so random access has a linear cost in the numbers of elements in the list.
另一个重要的保证是每个不同容器在内存中存储其数据的方式:
请注意,双端队列的设计目的是尝试平衡向量和列表的优点,而没有各自的缺点。在内存有限的平台(例如微控制器)中,它是一个特别有趣的容器。
内存存储策略经常被忽视,然而,它往往是为特定应用选择最合适的容器的最重要原因之一。
Another important guarantee is the way each different container stores its data in memory:
Note that the deque was designed to try to balance the advantages of both vector and list without their respective drawbacks. It is a specially interesting container in memory limited platforms, for example, microcontrollers.
The memory storage strategy is often overlooked, however, it is frequently one of the most important reasons to select the most suitable container for a certain application.
不可以。双端队列只支持前后O(1)的插入和删除。例如,它可以在具有环绕的矢量中实现。由于它还保证 O(1) 随机访问,因此您可以确定它不使用(仅)双向链表。
No. A deque only supports O(1) insertion and deletion at the front and back. It may, for example, be implemented in a vector with wrap-around. Since it also guarantees O(1) random access, you can be sure it's not using (just) a doubly linked list.
deque
和list
之间的显着差异对于
deque
:并排存储的项目;
针对从两侧(正面、背面)添加数据进行了优化;
按数字(整数)索引的元素。
可以通过迭代器甚至元素的索引进行浏览。
访问数据的时间更快。
对于
列表
“随机”存储在内存中的项目;
只能通过迭代器浏览;
针对在中间插入和移除进行了优化。
由于其空间局部性非常差,数据的时间访问速度较慢,迭代速度较慢。
可以很好地处理大元素
您还可以检查以下内容 链接,它比较了两个STL容器(使用std::vector)之间的性能
希望我分享了一些有用的信息。
Among eminent differences between
deque
andlist
For
deque
:Items stored side by side;
Optimized for adding datas from two sides (front, back);
Elements indexed by numbers (integers).
Can be browsed by iterators and even by element's index.
Time access to data is faster.
For
list
Items stored "randomly" in the memory;
Can be browsed only by iterators;
Optimized for insertion and removal in the middle.
Time access to data is slower, slow to iterate, due to its very poor spatial locality.
Handles very well large elements
You can check also the following Link, which compares the performance between the two STL containers (with std::vector)
Hope i shared some useful informations.
其他人已经很好地解释了性能差异。我只是想补充一点,类似甚至相同的接口在面向对象编程中很常见——这是编写面向对象软件的通用方法的一部分。你绝对不应该仅仅因为两个类实现相同的接口而假设它们以相同的方式工作,就像你不应该假设马像狗一样工作,因为它们都实现了attack()和make_noise()。
The performance differences have been explained well by others. I just wanted to add that similar or even identical interfaces are common in object-oriented programming -- part of the general methodology of writing object-oriented software. You should IN NO WAY assume that two classes work the same way simply because they implement the same interface, any more than you should assume that a horse works like a dog because they both implement attack() and make_noise().
下面是使用列表、无序映射的概念验证代码,它提供 O(1) 查找和 O(1) 精确 LRU 维护。需要(非擦除)迭代器在擦除操作中幸存下来。计划在 O(1) 任意大的软件管理缓存中使用 GPU 内存上的 CPU 指针。向 Linux O(1) 调度程序致敬(LRU <-> 每个处理器的运行队列)。 unordered_map 通过哈希表具有恒定时间访问。
Here's a proof-of-concept code use of list, unorded map that gives O(1) lookup and O(1) exact LRU maintenance. Needs the (non-erased) iterators to survive erase operations. Plan to use in a O(1) arbitrarily large software managed cache for CPU pointers on GPU memory. Nods to the Linux O(1) scheduler (LRU <-> run queue per processor). The unordered_map has constant time access via hash table.