方法 | 功能 |
---|---|
insert(key) | 插入值为key的节点 |
erase(key) | 删除值为key的节点 |
get_pre(root) | 拿到root的前驱节点 |
left_rotate(root) | 以root为根进行左旋操作 |
right_rotate(root) | 以root为根进行右旋操作 |
has_red_child(root) | 判断root子节点是否是红色 |
insert_maintain(root) | 对插入操作的回溯进行调整 |
erase_maintain(root) | 对删除操作的回溯进行调整 |
完整代码如下:
NIL = Node(-1, 1, None, None)
NIL.left = NIL
NIL.right = NIL
class Node:
def __init__(self, key = -1, color = 0, left = NIL, right = NIL):
self.key = key
self.color = color
self.left = left
self.right = right
def __repr__(self):
return "[" + str(self.key) + "-" + str(self.color) + ": (" + str(self.left.key) + "-" + str(self.left.color) + ", " + str(self.right.key) + "-" + str(self.right.key) + ")]"
class RBTree:
def __init__(self, root = NIL):
self.root = root
def insert(self, key):
self.root = self.__insert(self.root, key)
self.root.color = 1
return self.root
def __insert(self, root, key):
if root == NIL:
return Node(key)
if root.key == key:
return root
if root.key < key:
root.right = self.__insert(root.right, key)
else:
root.left = self.__insert(root.left, key)
return self.insert_maintain(root)
def insert_maintain(self, root):
if not self.has_red_child(root):
return root
if root.left.color == 0 and root.right.color == 0:
if not self.has_red_child(root.left) and not self.has_red_child(root.right):
return root
root.color = 0
root.left.color = root.right.color = 1
return root
if root.left.color == 0 and not self.has_red_child(root.left):
return root
if root.right.color == 0 and not self.has_red_child(root.right):
return root
if root.left.color == 0:
if root.left.right.color == 0:
root.left = self.left_rotate(root.left)
root = self.right_rotate(root)
else:
if root.right.left.color == 0:
root.right = self.right_rotate(root.right)
root = self.left_rotate(root)
root.color = 0
root.left.color = root.right.color = 1
return root
def erase(self, key):
self.root = self.__erase(self.root, key)
self.root.color = 1
return self.root
def __erase(self, root, key):
if root == NIL:
return NIL
if root.key < key:
root.right = self.__erase(root.right, key)
elif root.key > key:
root.left = self.__erase(root.left, key)
else:
if root.left == NIL or root.right == NIL:
tmp = root.left if root.left != NIL else root.right
tmp.color += root.color
del root
return tmp
tmp = self.get_pre(root)
root.key = tmp.key
root.left = self.__erase(root.left, tmp.key)
return self.erase_maintain(root)
def erase_maintain(self, root):
if root.left.color != 2 and root.right.color != 2:
return root
if self.has_red_child(root):
root.color = 0
if root.left.color == 0:
root = self.right_rotate(root)
root.right = self.erase_maintain(root.right)
else:
root = self.left_rotate(root)
root.left = self.erase_maintain(root.left)
root.color = 1
return root
if root.left.color == 2 and not self.has_red_child(root.right) or root.right.color == 2 and not self.has_red_child(root.left):
root.left.color -= 1
root.right.color -= 1
root.color += 1
return root
if root.left.color == 2:
root.left.color = 1
if root.right.right.color != 0:
root.right.color = 0
root.right = self.right_rotate(root.right)
root.right.color = 1
root = self.left_rotate(root)
root.color = root.left.color
else:
root.right.color = 1
if root.left.left.color != 0:
root.left.color = 0
root.left = self.left_rotate(root.left)
root.left.color = 1
root = self.right_rotate(root)
root.color = root.right.color
root.left.color = root.right.color = 1
return root
def left_rotate(self, root):
tmp = root.right
root.right = tmp.left
tmp.left = root
return tmp
def right_rotate(self , root):
tmp = root.left
root.left = tmp.right
tmp.right = root
return tmp
def get_pre(self, root):
tmp = root.left
while tmp.right != NIL:
tmp = tmp.right
return tmp
def has_red_child(self, root):
return root.left.color == 0 or root.right.color == 0
def inorder(self, root):
if root.left != NIL:
self.inorder(root.left)
print(root)
if root.right != NIL:
self.inorder(root.right)
return None
测试代码:
t = RBTree()
for i in range(1, 7):
t.insert(i)
if i % 3 == 0:
t.erase(i - 1)
t.inorder(t.root)
🔴⚫️🌲
😊性质
- 每个节点非黑即红
- 根节点一定是黑色
- 叶子节点(NIL)是黑色
- 如果节点是红色,那么它的两个子节点都是黑色
- 从根节点到叶节点的所有路径,黑色节点数量相同
- 由性质4、5可推知:红黑树中,最长路径 == 2倍最短路径
💸Node
- NIL节点,作为空节点(叶子节点)使用,默认单重黑。这样便于操作
- 正常新建节点,默认color为红,这样最大程度不影响性质5
- 红节点:没有子节点 or 两个黑色子节点
- 黑节点:如果只有一个子节点,那么必定是红色
🔫RBTree
封装红黑树的主要方法插入
和删除
- 由于根节点到路径长度最坏相差一半,所以红黑树是一个基本平衡的二叉搜索树。
- 它没有AVL树那么绝对平衡,但是红黑树相比AVL旋转操作要少,而且删除操作也比AVL树效率更高。
👕insert
调整策略:
- 首先明确插入调整站在祖父节点看。(相当于做了一个
延时操作
) - 其次插入调整是为了解决两个红色节点相邻的问题
🐱Case1 🐱
黑红红: 采取红色上浮,变为红黑黑
🐶Case2🐶
黑红黑:LL失衡,大右旋(如下图2),变为红黑黑
🍗erase
调整策略:
-
红色节点
- 度0:直接删
- 度1:不存在
- 度2:转为前驱
-
黑色节点
- 度0:双黑顶替(延时)
- 度1:红色点互换
- 度2:转为前驱
- 首先明确删除调整是站在父节点 上
- 其次删除调整是为了调整双黑节点
🐯Case1🐯
兄弟黑+兄弟孩子黑:双黑上浮,黑红黑
🐻Case2🐻
兄弟黑+兄弟同侧孩子红:RR失衡,大左旋(如下图2),根变左孩子颜色(右旋右孩子),孩子都变黑,双黑少一重
🐼Case3🐼
同case2: 不过先小旋(新根变黑,老根变红),在大旋
- 如果兄弟红,那么就旋成黑,就可以啦(O(∩_∩)O)
不要忘了,每次插入或删除操作后,根强制为黑
💚💚💚为啥不是红绿树?💗💗💗