STL 容器底层原理:基于红黑树模拟实现 map 与 set
在深入理解 STL 关联式容器之前,我们需要先掌握红黑树的模拟实现。本文将以资深工程师的视角,从 STL 源码设计思路出发,逐步完善 map 和 set 的封装。
一、了解 STL 库中的 map/set 底层
map 和 set 是通过红黑树封装实现的。观察 STL 源码可以发现,它们都封装了一个类模板 rb_tree 的对象 rep_type。
1. set 的模板参数
set 中传入的 key_type 和 value_type 都是 Key 类型。虽然 set 只存储一个 key,但这里传入了两个相同的类型,这是为了泛型设计的统一性。
template<class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
typedef Key key_type;
typedef Key value_type;
private:
typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;
rep_type t;
};
2. map 的模板参数
map 中 key_type 是 Key 类型,而 value_type 是 pair<const Key, T>。这看似多余,实则是为了适配 rb_tree 的通用结构。
template<class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
typedef Key key_type;
typedef pair<const Key, T> value_type;
private:
typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t;
};
3. 为什么需要两个模板参数?
rb_tree 内部使用第二个模板参数 Value 定义节点实际存储的内容。map 传入 <Key, pair<Key,Value>>,则节点存 pair;set 传入 <Key, Key>,则节点存 Key。
第一个模板参数 Key 的存在是为了支持 find、erase 等接口。这些接口需要直接通过 key 值查找,而不必遍历整个 value 结构。如果仅依赖存储类型,map 的 find 将无法直接定义参数。因此,这种设计让 map 和 set 可以共用同一份 rb_tree 类模板,提高了代码复用率。


