簡體   English   中英

不同容器上的 std::stack 實現有什么實際區別?

[英]std::stack implementation on different containers what is the actual difference?

實現std::stack

有幾個選項,例如:

   // stack with default underlying deque
   std::stack< int > intDequeStack;   

   // stack with underlying vector
   std::stack< int, std::vector< int > > intVectorStack;

   // stack with underlying list
   std::stack< int, std::list< int > > intListStack;

當我從中得到的只是相同的操作“push、pop 和 top”時,在不同的容器上定義std::stack有什么優點和缺點?

換句話說:一堆雙端隊列和一堆向量和一堆列表之間有什么區別,為什么我要選擇除雙端隊列以外的任何東西?

堆棧繼承了底層容器的性能特征。

  • 對於最大大小可能不同的堆棧, std::vector是一個糟糕的選擇。 堆棧上的每次push都可能需要在向量中進行大量重新分配。 除非明確要求,否則向量也永遠不會縮小,因此如果堆棧變大然后縮小,則永遠不會釋放額外的 memory(直到堆棧被銷毀)。 但是,向量在它們和存儲的數據之間只有一層間接性。

    因此:如果您知道堆棧將達到的最大大小並且該大小相對較小,那么您在2上調用reserve()的向量在所有情況下都可能比列表或雙端隊列更快; 它具有非常好的數據局部性和訪問元素的更少的間接級別。

  • std::list是一個鏈表,因此堆棧在彈出1時將具有兩個間接級別,並且它將始終使用它需要多少 memory 。 push 沒有昂貴的重新分配,但它的數據局部性很差,因為每個節點都可以分配到堆中的任何位置; 處理堆棧中的大量數據將無法有效地使用各種 CPU memory 緩存,因為每個彈出可能需要跳轉到堆中完全不同的位置。

  • std::deque通過在一個結構(通常是一個鏈表)中維護一個短 arrays 的集合來結合兩者的某些方面。 因此,項目集群將具有良好的數據局部性,並且結構可以按需增長和縮小,因為 arrays 永遠不會重新分配——如果它需要更多空間,它會分配一個新數組並將其添加到開頭/結構結束。 它是向量和列表之間的一個很好的中間地帶,這就是為什么它是默認的。


1對數據有一級間接,但為了移除最后一個元素,鏈表需要對前一個節點進行另一次間接以清除下一個指針。

2請注意,您需要在構建容器時移動向量。 復制向量不一定保留其容量。 例如,您可以使用這個助手:

template <typename T>
std::stack<T, std::vector<T>> vector_stack(
    typename std::vector<T>::size_type capacity
) {
    std::vector<T> vec;
    vec.reserve(capacity);

    return std::stack<T, std::vector<T>>{std::move(vec)};
}

暫無
暫無

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

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