红黑树
来源:互联网 发布:bp神经网络算法 编辑:程序博客网 时间:2024/06/01 22:37
红黑树
红黑树,一种二叉查找树,但在每个节点上增加一个存储为表示节点的颜色,可以试Red或Black。通过对任何一条从根节点到叶子的路径上各个节点找色方式的限制,红黑树确保没有一条路径会比其它路径长出2倍,因而是接近平衡的。
二叉查找树
红黑树的5条性质
- 每个节点非红即黑
- 根节点是黑色
- 每个叶节点(NULL节点)都是黑色
- 如果一个节点是红色,那么它的两个儿子都是黑色
- 对任意节点而言,其到叶节点NULL指针的路径都包含相同数目的黑节点。
如下图所示:
红黑树旋转
当对红黑树进行了插入和删除操作,有可能会破坏红黑树的性质,因此需要调整数的结构,改变某些节点的颜色以及进行旋转操作,以使得红黑树继续维持它的5条性质。
左旋
LEFT-ROTATE(T, x) y ← right[x] // 前提:这里假设x的右孩子为y。下面开始正式操作 right[x] ← left[y] // 将 “y的左孩子” 设为 “x的右孩子”,即 将β设为x的右孩子 p[left[y]] ← x // 将 “x” 设为 “y的左孩子的父亲”,即 将β的父亲设为x p[y] ← p[x] // 将 “x的父亲” 设为 “y的父亲” if p[x] = nil[T] then root[T] ← y // 情况1:如果 “x的父亲” 是空节点,则将y设为根节点 else if x = left[p[x]] then left[p[x]] ← y // 情况2:如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子” else right[p[x]] ← y // 情况3:(x是它父节点的右孩子) 将y设为“x的父节点的右孩子” left[y] ← x // 将 “x” 设为 “y的左孩子” p[x] ← y // 将 “x的父节点” 设为 “y”
右旋
RIGHT-ROTATE(T, y) x ← left[y] // 前提:这里假设y的左孩子为x。下面开始正式操作 left[y] ← right[x] // 将 “x的右孩子” 设为 “y的左孩子”,即 将β设为y的左孩子 p[right[x]] ← y // 将 “y” 设为 “x的右孩子的父亲”,即 将β的父亲设为y p[x] ← p[y] // 将 “y的父亲” 设为 “x的父亲” if p[y] = nil[T] then root[T] ← x // 情况1:如果 “y的父亲” 是空节点,则将x设为根节点 else if y = right[p[y]] then right[p[y]] ← x // 情况2:如果 y是它父节点的右孩子,则将x设为“y的父节点的左孩子” else left[p[y]] ← x // 情况3:(y是它父节点的左孩子) 将x设为“y的父节点的左孩子” right[x] ← y // 将 “y” 设为 “x的右孩子” p[y] ← x // 将 “y的父节点” 设为 “x”
左旋和右旋对称。
区分左旋和右旋
左旋: 被旋转的节点将变成一个左节点
右旋: 被旋转的节点将变成一个右节点
二叉树插入
TREE-INSERT(T, z) y ← NIL x ← T.root while x ≠ NIL do y ← x if z.key < x.key then x ← x.left else x ← x.right z.p ← y if y == NIL then T.root ← z else if z.key < y.key then y.left ← z else y.right ← z
红黑树的插入
RB-INSERT(T, z) y ← nil x ← T.root while x ≠ T.nil do y ← x if z.key < x.key then x ← x.left else x ← x.right z.p ← y if y == nil[T] then T.root ← z else if z.key < y.key then y.left ← z else y.right ← z z.left ← T.nil z.right ← T.nil z.color ← RED RB-INSERT-FIXUP(T, z)
最后的步骤:把左孩子和右孩子都设置为nil,再把z节点设置为红色。最后调用RB-INSERT-FIXUP函数对其进行修正(重新找色和旋转)
RB-INSERT-FIXUP代码
RB-INSERT-FIXUP(T, z)while color[p[z]] = RED // 若“当前节点(z)的父节点是红色”,则进行以下处理。 do if p[z] = left[p[p[z]]] // 若“z的父节点”是“z的祖父节点的左孩子”,则进行以下处理。 then y ← right[p[p[z]]] // 将y设置为“z的叔叔节点(z的祖父节点的右孩子)” if color[y] = RED // Case 1条件:叔叔是红色 then color[p[z]] ← BLACK ▹ Case 1 // (01) 将“父节点”设为黑色。 color[y] ← BLACK ▹ Case 1 // (02) 将“叔叔节点”设为黑色。 color[p[p[z]]] ← RED ▹ Case 1 // (03) 将“祖父节点”设为“红色”。 z ← p[p[z]] ▹ Case 1 // (04) 将“祖父节点”设为“当前节点”(红色节点) else if z = right[p[z]] // Case 2条件:叔叔是黑色,且当前节点是右孩子 then z ← p[z] ▹ Case 2 // (01) 将“父节点”作为“新的当前节点”。 LEFT-ROTATE(T, z) ▹ Case 2 // (02) 以“新的当前节点”为支点进行左旋。 color[p[z]] ← BLACK ▹ Case 3 // Case 3条件:叔叔是黑色,且当前节点是左孩子。(01) 将“父节点”设为“黑色”。 color[p[p[z]]] ← RED ▹ Case 3 // (02) 将“祖父节点”设为“红色”。 RIGHT-ROTATE(T, p[p[z]]) ▹ Case 3 // (03) 以“祖父节点”为支点进行右旋。 else (same as then clause with "right" and "left" exchanged) // 若“z的父节点”是“z的祖父节点的右孩子”,将上面的操作中“right”和“left”交换位置,然后依次执行。color[root[T]] ← BLACK
根据被插入节点的父节点的情况,分为3中情况来处理:
1. 被插入的节点是根节点:可直接把此节点涂为黑色。
2. 被插入的节点的父节点是黑色:红黑树没有被破坏,无需修正。
3. 被插入的节点的父节点是红色:与特性4冲突(红色节点的两个儿子必须都是黑色)
针对情况3:被插入节点的父亲节点是红色,在这种情况下,其祖父节点一定存在,也存在一个叔叔节点。我们根据叔叔节点的情况,再进一步分为3种情况。
当前节点的父节点是红色
case1 叔叔节点也是红色
case2 叔叔节点是黑色,且当前节点是其父节点的右孩子
case3 叔叔节点是黑色,且当前节点是其父节点的左孩子
阅读全文
0 0
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 红黑树
- 【前端】html标签嵌套规则
- 使用Markdown编辑器写博客
- mfcbutton 使用
- IOS笔记(1)
- openssl 命令行
- 红黑树
- 哈希函数
- Eclipse中改变控制台字体格式的方法
- PKI和数字证书基本原理
- 5.5 NETWORK SECURITY
- Storm集群部署
- leetcode题解-153. Find Minimum in Rotated Sorted Array && 238. Product of Array Except Self
- Android根据系统意图安装apk
- 关于File文件类的使用: