基于红黑树的std::map
基本用法
(1)头文件与声明
#include <map>
#include <iostream>
#include <string>
int main() {
// 声明一个 std::map,键为 int,值为 std::string
std::map<int, std::string> studentMap;
return 0;
}
(2)插入元素
使用 insert 方法:
studentMap.insert({101, "Alice"}); // C++11 起支持列表初始化
使用下标运算符 [ ]:
studentMap[103] = "Charlie"; // 如果键不存在,会自动插入
(3)访问元素
使用 at 方法(安全访问):
std::string name = studentMap.at(101); // 如果键不存在,抛出 std::out_of_range 异常
std::cout << "Name: " << name << std::endl;
使用 [ ] 操作符(可能插入默认值):
std::string name = studentMap[104]; // 如果键不存在,会插入一个空字符串
(4)查找元素
使用 find 方法:
auto it = studentMap.find(102);
if (it != studentMap.end()) {
std::cout << "Found: ID " << it->first << ", Name " << it->second << std::endl;
} else {
std::cout << "Key not found." << std::endl;
}
find 返回一个迭代器,指向找到的元素或 end()。
(5)删除元素
通过键删除:
studentMap.erase(103); // 删除键为 103 的元素
通过迭代器删除:
auto it = studentMap.find(102);
if (it != studentMap.end()) {
studentMap.erase(it); // 删除迭代器指向的元素
}
删除范围:
studentMap.erase(studentMap.begin(), studentMap.find(102)); // 删除 [begin, 102) 范围内的元素
底层实现
std::map 是 C++ 标准库中的有序关联容器,其底层实现基于红黑树(Red-Black Tree),这是一种自平衡的二叉搜索树(Balanced Binary Search Tree)。
左子树节点值<=根节点值<=右子树节点值
红黑树必须满足以下五个性质:
1.节点颜色:每个节点只能是红色或者黑色。
2.根节点颜色:根节点必须是黑色。
3.叶子节点颜色:所有叶子节点(NIL节点,即空节点)都是黑色的。
4.红色节点子节点颜色:如果一个节点是红色的,则它的两个子节点必须是黑色的。这意味着不能有两个连续的红色节点出现在从根节点到叶子节点的任何路径上。
5.黑色节点数量:从一个节点到该节点的所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。这确保了红黑树的高度近似平衡。
红黑树的插入
左旋
定义
左旋是针对某个节点(设为 x)的右子节点(设为 y)进行的操作。通过调整指针关系,将 y 提升为父节点,x 变为 y 的左子节点,同时保持二叉搜索树的性质不变。
操作步骤
保存关键节点:
y = x->right(x 的右子节点 y)
T = y->left(y 的左子树 T)
调整指针:
y->left = x(y 的左子节点指向 x)
x->right = T(x 的右子节点指向 T)
更新父指针:
若 T 非空,T->parent = x
y->parent = x->parent(将 y 连接到原 x 的位置)
x->parent = y
右旋
定义
右旋是针对某个节点(设为 y)的左子节点(设为 x)进行的操作。通过调整指针关系,将 x 提升为父节点,y 变为 x 的右子节点,同时保持二叉搜索树的性质不变。
操作步骤
保存关键节点:
x = y->left(y 的左子节点 x)
T = x->right(x 的右子树 T)
调整指针:
x->right = y(x 的右子节点指向 y)
y->left = T(y 的左子节点指向 T)
更新父指针:
若 T 非空,T->parent = y
x->parent = y->parent(将 x 连接到原 y 的位置)
y->parent = x
规则
先查找,确定插入的位置,插入新节点
新节点是根节点,染为黑色
新节点是非根节点,然为红色
若插入新节点依然满足红黑树定义,则插入结束
若插入新节点依然不满足红黑树定义,需要调整
情况 | 条件 | 调整 |
---|---|---|
0 | N是根节点 | 将N染黑 |
1 | 黑叔叔 | ll型:右单旋,染色 |
2 | 黑叔叔 | rr型:左单旋,染色 |
3 | 黑叔叔 | lr型:左右双旋,染色 |
4 | 黑叔叔 | rl型:左右双旋,染色 |
5 | 红叔叔 | 染色 |
std::map 的节点结构
每个节点存储以下信息:
struct Node {
Color color; // 节点颜色(红或黑)
Key key; // 键(不可修改)
Value value; // 值(可修改)
Node* parent; // 父节点指针
Node* left; // 左子节点指针
Node* right; // 右子节点指针
};
实现优势
有序性:键始终按严格弱序(默认 <)排列,支持顺序遍历和范围查询。
稳定性:插入/删除操作不会使迭代器失效(除非删除当前元素)。
内存效率:无需预分配内存,动态调整树结构。