std::deque(雙端隊列)在 C++ 開發中使用率遠低於 vector 與 list,但從綜合性能指標看,它是基於值語義容器中綜合表現最優的選擇。本文剖析其分段連續數據結構,對比 vector/list 的時空複雜度,並說明為何 std::TextPool(基於 deque 實現)同樣受益於這一設計。
deque 內部維護一個「塊指針數組」(vector<Block*>),每塊固定大小(典型 512 元素),首尾兩塊可能部分填充,故需額外迭代器 m_first、m_last 標記邊界:
template <class _E>
class deque {
enum { BlockSize = 512 };
typedef _E Block[BlockSize];
std::vector<Block*> m_storage; // 塊指針動態數組
iterator m_first, m_last; // 邊界迭代器
};
這種「介於數組與鏈表之間」的結構,賦予了 deque 獨特的性能特徵。
| 操作 | vector | list | deque |
|---|---|---|---|
push_back | 攤還 O(1)(2倍擴容模型),但需搬移數據 | O(1),需分配節點 | 攤還 O(1),僅偶爾搬移塊指針數組(極小開銷) |
push_front | 不支持(O(N)) | O(1) | O(1),對稱高效 |
operator[] | O(1),單次內存訪問 | O(N),需遍歷 | O(1),m_storage[i/BlockSize][i%BlockSize],僅多一次間接訪問 |
deque 的塊指針數組極小(海量數據下僅數千指針),擴容搬移成本可忽略,空間利用率極高。
關鍵差異: deque 在無 insert/erase 情況下,push_back/push_front 不會導致現有元素地址失效;vector 則會因擴容搬移導致引用/指針失效。
// vector:危險
std::vector<int> vec; int& ref = vec[0]; vec.push_back(1); ref = 99; // UB!
// deque:安全
std::deque<int> dq; int& ref = dq[0]; dq.push_back(1); ref = 99; // OK
注意: 迭代器在 push_back/push_front 後仍會失效,僅元素地址(裸指針/引用)穩定。
deque(及基於它的 TextPool)vector 配合 reserve()listdeque 兼具數組的隨機訪問與鏈表的雙端高效,是大數據場景下的「瑞士軍刀」,值得提升使用優先級。