簡單比較下 std::map、std::unordered_map 和 protobuf::Map 的性能,主要關注在 插入、查找 和 刪除 操作上的效率以及內存管理的差異。
std::map
- 底層實現:std::map 使用紅黑樹作為底層數據結構,紅黑樹是一種平衡二叉查找樹的變體結構,它的左右子樹的高度差有可能會大于 1。所以紅黑樹不是嚴格意義上的平衡二叉樹AVL,但對之進行平衡的代價相對于AVL較低, 其平均統計性能要強于AVL。紅黑樹具有自動排序的功能,因此它使得map也具有按key排序的功能,因此在map中的元素排列都是有序的。在map中,紅黑樹的每個節點就代表一個元素,因此實現對map的增刪改查,也就是相當于對紅黑樹的操作。對于這些操作的復雜度都為O(logn),復雜度即為紅黑樹的高度。
- 插入、查找、刪除性能:由于是有序的,對于大數據量場景,樹結構的操作時間更長。
- 內存管理:std::map 內存占用較高,因為紅黑樹的每個節點都需要額外的指針存儲,且樹的平衡機制需要更多的內存管理。
- 適用場景:顯然std::map 適合需要數據有序存儲的情況。
std::unordered_map
- 底層實現:std::unordered_map 使用哈希表(hash table)作為底層數據結構,平均操作時間復雜度為 O(1),但最差情況下可能退化到 O(n)。key值是無序的。
- 插入、查找、刪除性能:在平均情況下,std::unordered_map 的性能通常優于 std::map,適合頻繁的插入和查找操作。
- 內存管理:哈希表在空間分配上通常會預分配一部分空間,以減少重哈希和再分配的頻率。不過當哈希碰撞較多時,內存消耗會增加。
- 適用場景:std::unordered_map 適合不關心順序,但需要高效查找和插入操作的場景。
protobuf::Map
- 底層實現:protobuf::Map 的具體實現網上搜索不到,但基于官方的Protobuf 文檔(https://protobuf.dev/reference/cpp/api-docs/google.protobuf.map/), std::unordered_map,使用了哈希表來實現。
- 插入、查找、刪除性能:protobuf::Map 在 Protobuf 序列化、反序列化場景中的性能優于 std::map 和 std::unordered_map,因為它直接支持二進制序列化,減少了額外的序列化和轉換成本。
- 內存管理:protobuf::Map 為序列化和反序列化進行內存管理優化,減少了 Protobuf 數據格式和 C++ 容器之間的冗余轉換,因此在存儲大數據集或頻繁數據交換時,內存消耗更低。
- 適用場景: 相比 std::map 和 std::unordered_map,對于不在乎順序的場景而言,protobuf::Map 與 std::unordered_map性能差不多,但考慮到序列化時間和內存占用,直接使用protobuf::Map可能會比較合適。
參考資料
- https://protobuf.dev/reference/cpp/api-docs/google.protobuf.map/
- https://stackoverflow.com/questions/3902644/choosing-between-stdmap-and-stdunordered-map
- https://www.geeksforgeeks.org/map-vs-unordered_map-c/
- https://medium.com/@yakupcengiz/comparing-std-map-and-std-unordered-map-in-c-92aa18c5dc39
- chatgpt answer: