defleft_rotate(self, node): ''' 左旋操作,分为三步: 1. 将 r.parent 置为 p(可能会更新 root),根据 node 的位置把 r 连接至 p.left 或 p.right 2. 将 node.parent 置为 r,r.left 置为 node 3. 将 node.right 置为 rl,若 rl 存在,将 rl.parent 置为 node, * 左旋示意图:对节点x进行左旋 * p p * / / * node r * / \ / \ * x r -----> node rr * / \ / \ * rl rr x rl '''
p = node.parent r = node.right rl = r.left
# 1 r 连到父节点,若父节点为空(node 为 root),更新 root r.parent = p ifnot p: self.root = r else: # 1.1 根据 node 相对于 p 的位置来连接 p 与 r if (p.left == node): p.left = r else: p.right = r
# 2. 连接 node 与 r node.parent = r r.left = node # 3. 连接 rl 与 node node.right = rl if (rl): rl.parent = node
defright_rotate(self, node): ''' 右旋操作,分为三步: 1. 将 l.parent 置为 p(可能会更新 root),根据 node 的位置把 l 连接至 p.left 或 p.right 2. 将 node.parent 置为 l,l.right 置为 node 3. 将 node.left 置为 lr,若 lr 存在,将 lr.parent 置为 node, * 右旋示意图:对节点y进行右旋 * p p * / / * node l * / \ / \ * l r -----> ll node * / \ / \ * ll lr lr r ''' p = node.parent l = node.left lr = l.right
l.parent = p ifnot p: self.root = l else: if (p.left == node): p.left = l else: p.right = l
与插入操作中的定义类似,这里以 N 代表 temp_node,S 代表 N 的兄弟节点,P 代表 N 与 S 的父节点,SL 与 SR 分别代表 S 的左右子节点,节点 S 的同侧儿子表示的情况为:若 S 为 P 的左儿子,则 S 的左儿子为 S 的同侧儿子 ( SL ),反之 SR 为同侧儿子,异侧儿子定义类似。
红黑树修复有以下六种情况:
N 为新的根节点
这说明原始被删除节点即为根节点,这种情况相当于所有路径均少了一个黑色的节点,我们将 N 变为黑色,即完成操作。
S 为红色
这种情况下无法直接处理,需要在 P 上做旋转,转换为其他情况。
P、S、SL、SR 均为黑色
这种情况下无法在这个局部结构中新增一个黑色节点(牢记我们的目标,在 N 的路径上增加一个黑色节点),此时只能将 S 变为红色,这样会使得局部结构达到平衡(左右都少了一个黑色节点),但红黑树整体依然不平衡。需要继续向上调整,试图在更上层的结构中为这条路径增加一个黑色节点。
因此,以 P 作为 delete_fix 的参数,改为处理 P 节点。至于为什么要处理该节点,牢记:delete_fix 的作用为使过 temp_node 节点的路径增加一个黑色节点,同时保证其他路径的黑色节点数目不变,在上述的调整过程中,我们通过改变 S 的颜色的方式使这个局部结构达到了平衡,但相较于其他路径都少了一个黑色节点,因此需要处理 P 节点,使得通过 P 节点的路径增加一个黑色节点,以平衡红黑树。
S、SL、SR 均为黑色,P 为红色
这种情况比较好处理,简单地将 S 变为红色再将 P 变为黑色,就能使得 N 的路径上多出一个黑色节点,而其他路径黑色节点数量不变。
defprintTree(self, color = True): defmaxDepth(root): if root == self.TNULL: return -1 leftDepth = maxDepth(root.left) rightDepth = maxDepth(root.right) returnmax(leftDepth, rightDepth) + 1 h = maxDepth(self.root) m = h + 1 n = pow(2, m) - 1 res = [[""for i inrange(n)] for i inrange(m)] nodes = [(self.root, 0, (n-1)//2)] while nodes: cur, r, c = nodes.pop() res[r][c] = str(cur.val) if color: res[r][c] += "r"if cur.color == 1else"b" if cur.left != self.TNULL: nodes.append((cur.left, r+1, c-pow(2,h-r-1))) if cur.right != self.TNULL: nodes.append((cur.right, r+1, c+pow(2,h-r-1))) return res
将一个列表插入红黑树
1 2 3
definsert_list(self, l): for i in l: self.insert_node(i)
中序遍历树
1 2 3 4 5 6 7 8 9
deftree2list(self): res = [] defhelper(node): if node isNone: return helper(node.left) res.append(node.val) helper(node.right) helper(self.root) return res
defprintTree(self, color = True): defmaxDepth(root): if root == self.TNULL: return -1 leftDepth = maxDepth(root.left) rightDepth = maxDepth(root.right) returnmax(leftDepth, rightDepth) + 1 h = maxDepth(self.root) m = h + 1 n = pow(2, m) - 1 res = [[""for i inrange(n)] for i inrange(m)] nodes = [(self.root, 0, (n-1)//2)] while nodes: cur, r, c = nodes.pop() res[r][c] = str(cur.val) if color: res[r][c] += "r"if cur.color == 1else"b" if cur.left != self.TNULL: nodes.append((cur.left, r+1, c-pow(2,h-r-1))) if cur.right != self.TNULL: nodes.append((cur.right, r+1, c+pow(2,h-r-1))) return res
defleft_rotate(self, node): ''' 左旋操作,分为三步: 1. 将 r.parent 置为 p(可能会更新 root),根据 node 的位置把 r 连接至 p.left 或 p.right 2. 将 node.parent 置为 r,r.left 置为 node 3. 将 node.right 置为 rl,若 rl 存在,将 rl.parent 置为 node, * 左旋示意图:对节点x进行左旋 * p p * / / * node r * / \ / \ * x r -----> node rr * / \ / \ * rl rr x rl '''
p = node.parent r = node.right rl = r.left
# 1 r 连到父节点,若父节点为空(node 为 root),更新 root r.parent = p ifnot p: self.root = r else: # 1.1 根据 node 相对于 p 的位置来连接 p 与 r if (p.left == node): p.left = r else: p.right = r
# 2. 连接 node 与 r node.parent = r r.left = node # 3. 连接 rl 与 node node.right = rl if (rl != self.TNULL): rl.parent = node
defright_rotate(self, node): ''' 右旋操作,分为三步: 1. 将 l.parent 置为 p(可能会更新 root),根据 node 的位置把 l 连接至 p.left 或 p.right 2. 将 node.parent 置为 l,l.right 置为 node 3. 将 node.left 置为 lr,若 lr 存在,将 lr.parent 置为 node, * 右旋示意图:对节点y进行右旋 * p p * / / * node l * / \ / \ * l r -----> ll node * / \ / \ * ll lr lr r ''' p = node.parent l = node.left lr = l.right
l.parent = p ifnot p: self.root = l else: if (p.left == node): p.left = l else: p.right = l
node.parent = l l.right = node
node.left = lr if (lr != self.TNULL): lr.parent = node
definsert_list(self, l): for i in l: self.insert_node(i) deftree2list(self): res = [] defhelper(node): if node == self.TNULL: return helper(node.left) res.append(node.val) helper(node.right) helper(self.root) return res
1 2 3 4
import random t = RB_Tree() t.insert_list([ random.randint(0, 100) for i inrange(10) ]) t.printTree()
definsert_test(epoch = 10, num = 100): print("=== insert test ==") for _ inrange(epoch): t = RB_Tree() curList = [random.randint(0, 1000) for _ inrange(num)] t.insert_list(curList) curList.sort() ans = "pass"if curList == t.tree2list() else"fail" print(f"======[{ans}]======")
defremove_test(epoch = 10, num = 100): print("=== remove test ==") for _ inrange(epoch): t = RB_Tree() curList = [random.randint(0, 1000) for _ inrange(num)] t.insert_list(curList) ans = True for _ inrange(random.randint(1, 10)): key = random.choice(curList) curList.remove(key) t.delete_node(key) curList.sort() ans = ans and (curList == t.tree2list()) ans = "pass"if ans else"fail" print(f"======[{ans}]======")