【发布时间】:2017-12-26 03:42:59
【问题描述】:
我不断从人们和文档中听到 std::deque 是像 std::vector 一样的随机访问,并且是像链表一样的恒定时间插入和删除。此外,与向量不同,std::deque 可以在恒定时间内在开头和结尾插入元素。我不确定标准是否指定了 std::deque 的特定实现,但它应该代表双端队列,并且很可能该实现将类似向量的分配缓冲区与指针链接在一起。一个关键的区别是元素不像 std::vector 那样连续。
鉴于它们不是连续的,当人们说它们是像向量一样的随机访问时,我是否认为他们的意思是“摊销”而不是实际上作为向量?这是因为向量只涉及一个偏移地址,保证每次真正的恒定时间访问,而双端队列必须计算所请求元素在序列中的距离,并计算沿它必须有多少链接缓冲区go 以找到该特定元素。
同样,在链表中的插入只涉及断开一个链接并设置另一个链接,而在双端队列中的插入(不是最后一个或第一个成员,必须至少在对于该特定链接缓冲区,插入点至少指向一个位置。因此,例如,如果一个链接缓冲区有 10 个成员,并且您碰巧在该特定缓冲区的开头插入,那么它必须至少移动 10 个成员(如果它更糟超出缓冲区容量,不得不重新分配)。
我有兴趣知道这一点,因为我想实现一个队列,而在标准库中,std::queue 就是他们所说的容器适配器,这意味着我们不会确切地知道它是什么容器类型,只要因为它以队列的方式运行。我认为它通常是 std::deque 或 std::list 的一种包装器。鉴于我只对先进先出的简单功能感兴趣,我几乎可以肯定链表在插入队列和从末尾弹出时会更快。所以我很想明确选择它而不是 std::queue。
另外,我知道链表在迭代时对缓存不太友好,但我们将链表与向量而不是双端队列进行比较,据我所知,这必须做相当大的工作记录保存的数量,以便在迭代时知道它在多远以及在哪个特定缓冲区中。
编辑:我刚刚发现对另一个感兴趣的问题的评论:
“我见过的 C++ 实现使用了一个指针数组 固定大小的数组。这实际上意味着 push_front 和 push_back 不是真正的恒定时间,而是智能增长 因素,你仍然得到摊销常数时间,所以 O(1) 不是 如此错误,实际上它比矢量更快,因为你是 交换单个指针而不是整个对象(以及更少的指针 比对象)。 – Matthieu M. 2011 年 6 月 9 日"
【问题讨论】:
-
"std::queue 是他们所说的容器适配器,这意味着我们不知道它是什么容器类型" -- @987654322 使用的底层容器@ 可通过模板参数进行配置。默认为
deque<T>。 -
deque 在中间没有固定时间插入,只有在末端。
-
@T.C 谢谢,我刚刚看到:“对于涉及频繁插入或删除除开头或结尾以外的位置的元素的操作,双端队列的性能更差,迭代器和引用的一致性也较差而不是列表和转发列表。”
-
事实证明只在结尾和开头插入分期常数,如果我链接的那个图是真的,那么在开头插入平均比在结尾插入要慢。
标签: c++ vector linked-list std deque