一颗红黑树,两种容器:揭秘 SGI-STL 中 map/set 的复用设计
·
一、源码框架分析(SGI-STL 设计思想)
SGI-STL30版本源代码,map和set源代码在map / set / stl_map.h / stl_set.h / stl_tree.h 等几个头文件中。
map和set的实现结构框架核心部分截取出来如下:







1.1 核心复用设计:一颗红黑树,两种容器

| 容器 | 传给 rb_tree 的模板参数 | 结点存储的数据类型 |
|---|---|---|
set | rb_tree<Key, Key, identity<Key>, ...> | Key(键即值) |
map | rb_tree<Key, pair<const Key, T>, select1st<pair>, ...> | pair<const Key, T>(键值对) |
关键洞察:
rb_tree的第二个模板参数Value决定了结点中存储什么数据,从而实现泛型——同一棵红黑树既能当 set 用,也能当 map 用。
1.2 为什么 set 要传两个相同的 Key 参数?
// set: 两个参数都是 Key
rb_tree<Key, Key, identity<Key>, ...>
// map: 第一个是 Key,第二个是 pair<Key, T>
rb_tree<Key, pair<const Key, T>, select1st<...>, ...>


二、模拟实现的核心步骤
2.1 解决"如何只比较 Key"的问题——KeyOfT 仿函数
因为 rb_tree 是泛型的,它不知道 T 到底是 K 还是 pair<K, V>,所以无法直接比较。需要在 map/set 层提供仿函数,从 T 中提取 Key:
// set 层:T 就是 K,直接返回
struct SetKeyOfT {
const K& operator()(const K& key) { return key; }
};
// map 层:T 是 pair<K, V>,返回 first
struct MapKeyOfT {
const K& operator()(const pair<K, V>& kv) { return kv.first; }
};
然后在 RBTree 的 Insert 中通过仿函数取出 Key 再比较:
KeyOfT kot;
if (kot(cur->_data) < kot(data)) { ... }


三、迭代器实现(重点难点)
3.1 迭代器是中序遍历的"游标"
map/set 的迭代器按 中序(左-根-右) 遍历,即升序顺序。
迭代器就是"中序遍历的游标"。它不像数组那样内存连续、直接
++就行,红黑树是分散在内存中的结点,必须通过逻辑计算找到"下一个"。





operator++ 的两条规则(记住!!!)
| 情况 | 操作 | 原因 |
|---|---|---|
| 右子树不为空 | 跳到右子树的最左结点 | 中序规则:根 → 右子树,右子树第一个是最左 |
| 右子树为空 | 向上找,直到当前结点是父亲的左孩子 | 说明当前子树访问完了,要回到祖先 |
3.2 operator++ 的核心逻辑
| 情况 | 操作 | 示例 |
|---|---|---|
| 右子树不为空 | 跳到右子树的最左结点 | it=18,右子树有 30,跳到 25(30的左子树最左) |
| 右子树为空 | 沿父节点向上找,直到当前结点是父节点的左孩子 | it=15(10的右),往上找,10 是 18 的 |
Self& operator++() {
if (_node->_right) {
// 右子树不空:找右子树最左
Node* leftMost = _node->_right;
while (leftMost->_left) leftMost = leftMost->_left;
_node = leftMost;
} else {
// 右子树为空:找"孩子是父亲左"的那个祖先
Node* cur = _node, *parent = cur->_parent;
while (parent && cur == parent->_right) {
cur = parent;
parent = cur->_parent;
}
_node = parent; // 可能是 nullptr(即 end)
}
return *this;
}





3.3 operator-- 的核心逻辑(与 ++ 对称表格
| 情况 | 操作 |
|---|---|
*this == end()(_node == nullptr) | 特殊处理:跳到整棵树的最右结点 |
| 左子树不为空 | 跳到左子树的最右结点 |
| 左子树为空 | 沿父节点向上找,直到当前结点是父节点的右孩子 |
3.4 end() 的表示
-
简化版:用
nullptr表示end() -
STL 源码版:增加哨兵位头结点
header,header的左指向最左结点,右指向最右结点,根的父亲指向header,header的父亲指向根



四、map 支持 operator[]
前提:insert 必须返回 pair<iterator, bool>(迭代器 + 是否插入成功)
V& operator[](const K& key) {
pair<iterator, bool> ret = insert(make_pair(key, V()));
// 如果 key 存在,返回对应迭代器的 value 引用
// 如果 key 不存在,插入默认值后返回其 value 引用
return ret.first->second;
}
- map要支持 [ ] 主要修改 insert 返回值支持 , 修改RBtree中 insert 返回值为 pair <Iterator , bool > Insert(const T&data)
- 有了 insert 支持 [ ] 实现就很简单了 , 具体参考如下代码:
RBTree.h
#pragma once
#include <utility>
#include <iostream>
using namespace std;
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
T _data;
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
Colour _col;
RBTreeNode(const T& data)
: _data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
{}
};
template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
Node* _root;
RBTreeIterator(Node* node, Node* root)
:_node(node)
,_root(root)
{}
Self& operator++()
{
if (_node->_right)
{
// 右不为空,右子树最左结点就是中序第一个
Node* leftMost = _node->_right;
while (leftMost->_left)
{
leftMost = leftMost->_left;
}
_node = leftMost;
}
else
{
// 孩子是父亲左的那个祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
if (_node == nullptr) // end()
{
// --end(),特殊处理,走到中序最后一个结点,整棵树的最右结点
Node* rightMost = _root;
while (rightMost && rightMost->_right)
{
rightMost = rightMost->_right;
}
_node = rightMost;
}
else if (_node->_left)
{
// 左子树不为空,中序左子树最后一个
Node* rightMost = _node->_left;
while (rightMost->_right)
{
rightMost = rightMost->_right;
}
_node = rightMost;
}
else
{
// 孩子是父亲右的那个祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s._node;
}
};
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef RBTreeIterator<T, T&, T*> Iterator;
typedef RBTreeIterator<T, const T&, const T*> ConstIterator;
Iterator Begin()
{
Node* leftMost = _root;
while (leftMost && leftMost->_left)
{
leftMost = leftMost->_left;
}
return Iterator(leftMost, _root);
}
Iterator End()
{
return Iterator(nullptr, _root);
}
ConstIterator Begin() const
{
Node* leftMost = _root;
while (leftMost && leftMost->_left)
{
leftMost = leftMost->_left;
}
return ConstIterator(leftMost, _root);
}
ConstIterator End() const
{
return ConstIterator(nullptr, _root);
}
RBTree() = default;
~RBTree()
{
Destroy(_root);
_root = nullptr;
}
pair<Iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(Iterator(_root, _root), true);
}
KeyOfT kot;
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) < kot(data))
{
parent = cur;
cur = cur->_right;
}
else if (kot(cur->_data) > kot(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(Iterator(cur, _root), false);
}
}
cur = new Node(data);
Node* newnode = cur;
// 新增结点。颜色红色给红色
cur->_col = RED;
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
// g
// p u
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
// u存在且为红 -》变色再继续往上处理
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
// u存在且为黑或不存在 -》旋转+变色
if (cur == parent->_left)
{
// g
// p u
//c
//单旋
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p u
// c
//双旋
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
// g
// u p
Node* uncle = grandfather->_left;
// 叔叔存在且为红,-》变色即可
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
else // 叔叔不存在,或者存在且为黑
{
// 情况二: 叔叔不存在或者存在且为黑
// 旋转+变色
// g
// u p
// c
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// u p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(Iterator(newnode, _root), true);
}
Iterator Find(const K& key)
{
KeyOfT kot;
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) < key)
{
cur = cur->_right;
}
else if (kot(cur->_data) > key)
{
cur = cur->_left;
}
else
{
return Iterator(cur, _root);
}
}
return End();
}
private:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* parentParent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (parentParent == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* parentParent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (parentParent == nullptr)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subL;
}
else
{
parentParent->_right = subL;
}
subL->_parent = parentParent;
}
}
void Destroy(Node* root)
{
if (root == nullptr)
return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
private:
Node* _root = nullptr;
};
MySet.h
#pragma once
#include"RBTree.h"
namespace bit
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;
typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
const_iterator begin() const
{
return _t.Begin();
}
const_iterator end() const
{
return _t.End();
}
pair<iterator, bool> insert(const K& key)
{
return _t.Insert(key);
}
iterator find(const K& key)
{
return _t.Find(key);
}
private:
RBTree<K, const K, SetKeyOfT> _t;
};
void Print(const set<int>& s)
{
set<int>::const_iterator it = s.end();
while (it != s.begin())
{
--it;
// 不支持修改
//*it += 2;
cout << *it << " ";
}
cout << endl;
}
void test_set()
{
set<int> s;
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
s.insert(e);
}
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
Print(s);
}
}
MyMap.h
#pragma once
#include"RBTree.h"
#include <string>
namespace bit
{
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
const_iterator begin() const
{
return _t.Begin();
}
const_iterator end() const
{
return _t.End();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
iterator find(const K& key)
{
return _t.Find(key);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};
void test_map()
{
map<string, string> dict;
dict.insert({ "sort", "排序" });
dict.insert({ "left", "左边" });
dict.insert({ "right", "右边" });
dict["left"] = "左边,剩余";
dict["insert"] = "插入";
dict["string"];
map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{
//不能修改first,可以修改second
//it->first += 'x';
it->second += 'x';
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
}
main 测试调用示例
#include"MySet.h"
#include"MyMap.h"
int main()
{
bit::test_set();
bit::test_map();
return 0;
}
五、key 不可修改的设计
5.1 set:所有元素不可修改
// 第二个模板参数传 const K
RBTree<K, const K, SetKeyOfT> _t;
// 这样 iterator 的 Ref = const K&,解引用返回常量引用
5.2 map:key 不可改,value 可改
// pair 的第一个参数加 const
RBTree<K, pair<const K, V>, MapKeyOfT> _t;
// 这样 it->first 是 const,it->second 可以修改
| 知识点 | 要点 |
|---|---|
| 泛型复用 | 同一棵红黑树通过模板参数 T 的不同,同时支持 set 和 map |
| KeyOfT 仿函数 | 解决 "不知道 T 是 K 还是 pair" 的比较问题,只提取 Key 比较 |
| 迭代器++/-- | 基于中序遍历的局部逻辑,不看全局只看当前子树的下一个/上一个 |
| const 设计 | 通过模板参数控制:set 全 const,map 的 key 为 const |
| insert 返回值 | pair<iterator, bool> 是支持 operator[] 的基础 |
| header 哨兵位 | STL 源码技巧,简化边界处理(最左/最右/end 的表示) |
更多推荐



所有评论(0)