std::map红黑树规则与修复
红黑树的规则
红黑树通过以下 5条规则 保持平衡:
- 颜色 规则:每个节点是 红色 或 黑色。
- 根节点规则:根节点必须是 黑色。
- 叶子节点规则:叶子节点(NIL 节点,空节点)是 黑色。
- 红色节点规则:红色节点的子节点必须是 黑色(即不能有连续的红色节点)。
- 黑色高度规则:从任意节点到其所有叶子节点的路径上,黑色节点的数量相同(称为 黑高)。
红黑树的插入与修复
当插入一个新节点时,红黑树可能违反规则,需要通过 颜色调整 和 旋转 来修复。
插入步骤
- 按BST规则插入:新节点初始为 红色(减少对黑高的影响)。
- 修复颜色冲突:如果父节点是红色,违反规则4,需要调整。
修复操作的3种情况
- Case 1:叔叔节点是红色。
- 将父节点和叔叔节点变为黑色,祖父节点变为红色。
- Case 2:叔叔节点是黑色,且新节点是父节点的右子节点。
- 对父节点左旋,转为 Case 3。
- Case 3:叔叔节点是黑色,且新节点是父节点的左子节点。
- 将父节点变黑,祖父节点变红,然后对祖父节点右旋。
举例
以下是向 std::map(底层红黑树)中插入节点的详细过程示例。假设我们要依次插入键 10、20、30、5、15,并逐步展示红黑树的调整过程。
插入步骤详解
1. 插入第一个节点 10
• 规则:根节点必须是黑色。
• 操作:直接插入为根节点,颜色设为黑色。
• 树结构:
10(B)
/ \
NIL NIL
2. 插入第二个节点 20
• 插入规则:新节点初始为红色。
• 操作:20 作为 10 的右子节点插入,颜色为红色。
• 检查冲突:父节点 10 是黑色,没有违反规则。
• 树结构:
10(B)
/ \
NIL 20(R)
/ \
NIL NIL
3. 插入第三个节点 30
• 插入位置:30 作为 20 的右子节点插入,颜色为红色。
• 冲突检查:
• 父节点 20(R) 是红色,违反规则4(红色节点的子节点必须为黑色)。
• 叔叔节点是 NIL(黑色,属于规则3的叶子节点)。
• 修复操作:进入 Case 2 → Case 3。
Case 2:叔叔节点是黑色,新节点是父节点的右子节点
• 操作:对父节点 20(R) 左旋。
• 旋转后结构:
10(B)
\
30(R)
/
20(R)
Case 3:叔叔节点是黑色,新节点是父节点的左子节点
• 操作:
- 将父节点
30(R)变为黑色。 - 将祖父节点
10(B)变为红色。 - 对祖父节点
10(B)右旋。
• 最终结构:
20(B)
/ \
10(R) 30(R)
4. 插入第四个节点 5
• 插入位置:5 作为 10(R) 的左子节点插入,颜色为红色。
• 冲突检查:
• 父节点 10(R) 是红色。
• 叔叔节点是 30(R)(红色)。
• 修复操作:进入 Case 1。
Case 1:叔叔节点是红色
• 操作:
- 将父节点
10(R)和叔叔节点30(R)变为黑色。 - 将祖父节点
20(B)变为红色。
• 最终结构:
20(R)
/ \
10(B) 30(B)
/
5(R)
5. 插入第五个节点 15
• 插入位置:15 作为 10(B) 的右子节点插入,颜色为红色。
• 冲突检查:
• 父节点 10(B) 是黑色,没有冲突。
• 树结构:
20(R)
/ \
10(B) 30(B)
/ \
5(R) 15(R)
最终红黑树验证
- 根节点为黑色:当前根节点
20是红色(违反规则2)→ 需要修复。
• 修复:将根节点强制设为黑色。
20(B)
/ \
10(R) 30(B)
/ \
5(R) 15(R)
-
红色节点规则:
•10(R)的子节点5(R)和15(R)违反规则4(红色节点不能有红色子节点)→ 需要修复。 -
修复
10(R)的子节点冲突:
• 选择5(R)或15(R)进行修复,以5(R)为例:
◦ 父节点10(R)是红色,叔叔节点30(B)是黑色。
◦ 进入 Case 2 → Case 3。
◦ 最终结构:
20(B)
/ \
15(B) 30(B)
/
10(R)
\
5(R)
关键点总结
- 插入新节点:初始为红色,按BST规则插入。
- 冲突修复:
• Case 1:叔叔节点是红色 → 颜色翻转。
• Case 2:叔叔节点是黑色,且新节点是右子节点 → 左旋。
• Case 3:叔叔节点是黑色,且新节点是左子节点 → 右旋 + 颜色调整。 - 根节点强制黑色:最终确保根节点为黑色。
通过上述步骤,红黑树始终保持平衡,确保 std::map 的插入、删除和查找操作高效(O(log n))。
浙公网安备 33010602011771号