簡體   English   中英

deque如何具有攤銷的常數時間復雜度

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

我讀到這里從一個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)

我的問題是關於第2點。雙端隊列如何在結束或開始時進行攤銷?

據我所知, std::vector在最后插入時具有分攤的常量時間復雜度。 這是因為矢量是連續的並且是動態陣列。 因此,當最終用於push_back的內存不足時,它將分配一個全新的內存塊,將現有項目從舊位置復制到新位置,然后從舊位置刪除項目。 我理解的這個操作是攤銷不變的。 這如何適用於雙端隊列? 如何在雙端隊列的頂部和底部插入是否可以攤銷。 我的印象是它應該是常數O(1)。 我知道一個雙端隊列由內存塊組成。

deque的通常實現基本上是指向固定大小節點的指針的向量。

分配固定大小的節點顯然具有恆定的復雜性,因此非常容易處理 - 您只需分攤在該節點中的多個項目之間分配單個節點的成本,以便為每個節點獲得恆定的復雜性。

指針部分的向量是(稍微)更有趣的。 當我們分配足夠的固定大小節點時,指針向量已滿,我們需要增加向量的大小。 std::vector一樣,我們需要將其內容復制到新分配的向量中,因此它的增長必須遵循幾何(而不是算術)進度。 這意味着我們有更多的指針可以復制,我們的復制越來越少,因此復制指針的總時間保持不變。

作為旁注:“向量”部分通常被視為循環緩沖區,因此如果您將deque用作隊列,不斷添加到一端並從另一端移除不會導致重新分配向量 - - 這只意味着移動頭部和尾部指針,以跟蹤指定時間內哪些指針處於“活動狀態”。

(褻瀆)答案在於containers.requirements.general,23.2.1 / 2:

本條款中的所有復雜性要求僅根據所包含對象的操作數量來說明。

因此,重新分配指針數組不會被標准的復雜性保證所涵蓋,並且可能需要任意長的時間。 如前所述,它可能會在任何“理智”實現中為每個push_front() / push_back()調用(或等效修飾符)添加一個攤銷的常量開銷。 我不建議在RT-critical代碼中使用deque 通常,在RT場景中,您不希望無限制的隊列或堆棧(默認情況下在C ++中使用deque作為底層容器),無論是內存分配都可能失敗,因此您最有可能使用預分配的環緩沖區(例如Boost的circular_buffer )代替。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM