简体   繁体   English

deque如何具有摊销的常数时间复杂度

[英]How does deque have an amortized constant Time Complexity

I read here from the accepted answer that a std::deque has the following characteristic 我读到这里从一个std ::双端队列具有以下特点公认的答案

1- Random access - constant O(1)
2- Insertion or removal of elements at the end or beginning - amortized constant O(1)
3- Insertion or removal of elements - linear O(n)

My question is about point 2. How can a deque have an amortized constant insertion at the end or beginning? 我的问题是关于第2点。双端队列如何在结束或开始时进行摊销?

I understand that a std::vector has an amortized constant time complexity for insertions at the end. 据我所知, std::vector在最后插入时具有分摊的常量时间复杂度。 This is because a vector is continguous and is a dynamic array. 这是因为矢量是连续的并且是动态阵列。 So when it runs out of memory for a push_back at the end, it would allocate a whole new block of memory, copy existing items from the old location to the new location and then delete items from the old location. 因此,当最终用于push_back的内存不足时,它将分配一个全新的内存块,将现有项目从旧位置复制到新位置,然后从旧位置删除项目。 This operation I understand is amortized constant. 我理解的这个操作是摊销不变的。 How does this apply to a deque ? 这如何适用于双端队列? How can insertions at the top and bottom of a deque be amortized constant. 如何在双端队列的顶部和底部插入是否可以摊销。 I was under the impression that it was supposed to be constant O(1). 我的印象是它应该是常数O(1)。 I know that a deque is composed of memory chunks. 我知道一个双端队列由内存块组成。

The usual implementation of a deque is basically a vector of pointers to fixed-sized nodes. deque的通常实现基本上是指向固定大小节点的指针的向量。

Allocating the fixed-size node clearly has constant complexity, so that's pretty easy to handle--you just amortize the cost of allocating a single node across the number of items in that node to get a constant complexity for each. 分配固定大小的节点显然具有恒定的复杂性,因此非常容易处理 - 您只需分摊在该节点中的多个项目之间分配单个节点的成本,以便为每个节点获得恒定的复杂性。

The vector of pointers part is what's (marginally) more interesting. 指针部分的向量是(稍微)更有趣的。 When we allocate enough of the fixed-size nodes that the vector of pointers is full, we need to increase the size of the vector. 当我们分配足够的固定大小节点时,指针向量已满,我们需要增加向量的大小。 Like std::vector , we need to copy its contents to the newly allocated vector, so its growth must follow a geometric (rather than arithmetic) progression. std::vector一样,我们需要将其内容复制到新分配的向量中,因此它的增长必须遵循几何(而不是算术)进度。 This means that we have more pointers to copy we do the copying less and less frequently, so the total time devoted to copying pointers remains constant. 这意味着我们有更多的指针可以复制,我们的复制越来越少,因此复制指针的总时间保持不变。

As a side note: the "vector" part is normally treated as a circular buffer, so if you're using your deque as a queue, constantly adding to one end and removing from the other does not result in re-allocating the vector--it just means moving the head and tail pointers that keep track of which of the pointers are "active" at a given time. 作为旁注:“向量”部分通常被视为循环缓冲区,因此如果您将deque用作队列,不断添加到一端并从另一端移除不会导致重新分配向量 - - 这只意味着移动头部和尾部指针,以跟踪指定时间内哪些指针处于“活动状态”。

The (profane) answer lies in containers.requirements.general, 23.2.1/2: (亵渎)答案在于containers.requirements.general,23.2.1 / 2:

All of the complexity requirements in this Clause are stated solely in terms of the number of operations on the contained objects. 本条款中的所有复杂性要求仅根据所包含对象的操作数量来说明。

Reallocating the array of pointers is hence not covered by the complexity guarantee of the standard and may take arbitrarily long. 因此,重新分配指针数组不会被标准的复杂性保证所涵盖,并且可能需要任意长的时间。 As mentioned before, it likely adds an amortized constant overhead to each push_front() / push_back() call (or an equivalent modifier) in any "sane" implementation. 如前所述,它可能会在任何“理智”实现中为每个push_front() / push_back()调用(或等效修饰符)添加一个摊销的常量开销。 I would not recommend using deque in RT-critical code though. 我不建议在RT-critical代码中使用deque Typically, in an RT scenario, you don't want to have unbounded queues or stacks (which in C++ by default use deque as the underlying container) anyway, neither memory allocations that could fail, so you will be most likely using a preallocated ring buffer (eg Boost's circular_buffer ) instead. 通常,在RT场景中,您不希望无限制的队列或堆栈(默认情况下在C ++中使用deque作为底层容器),无论是内存分配都可能失败,因此您最有可能使用预分配的环缓冲区(例如Boost的circular_buffer )代替。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM