python - Rad black Tree
Posted darkchii
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python - Rad black Tree相关的知识,希望对你有一定的参考价值。
很久没写红黑树了,这次使用 python 实现了一遍。
class Rbtree(object): """ 红黑树 """ class NodePre(object): """ 定义红黑树节点基本属性 """ _color = {‘red‘: True, ‘black‘: False} def __init__(self, parent=None, color=None, value=None, null=False): self.parent = parent self.left = None self.right = None self.color = color self.value = value self.null = null def get_grandparent(self): """ 获取节点的祖父节点 :return: """ p = self.parent if p is None: return None return p.parent def get_sibling(self): """ 获取节点的兄弟节点 :return: """ p = self.parent if p is None: return None elif self == p.left: return p.right else: return p.left def get_uncle(self): """ 获取节点的叔父节点 :return: """ p = self.parent g = self.get_grandparent() if g is None: return None else: return p.get_sibling() def is_red(self) -> bool: """ 判断当前节点颜色是否为红色 :return: """ return self._color[self.color] def __init__(self): self.root = self.NodePre(color=‘black‘, null=True) def _find_minimum_node_(self, sub_lt): """ 查找节点子树中的最小节点 :param sub_lt: :return: """ lt = sub_lt while not lt.left.null: lt = lt.left return lt def _get_node_parent_(self, value): """ 获取树中值为 value 的父节点 :param value: :return: """ rt = self.root q = None while not rt.null: # 遍历树 q = rt # 确保遍历结束前获取到父节点 if rt.value > value: # 如果当前节点值大于给定值则往左子树查找 rt = rt.left else: # 反之则往右子树查找 rt = rt.right return q def _get_node_(self, value): """ 获取与给定值相等的节点 :param value: :return: """ rt = self.root while not rt.null: if rt.value > value: rt = rt.left elif rt.value < value: rt = rt.right else: # 如果相等,直接返回该值的节点 return rt return None def _left_rotate_(self, node): """ 节点左旋转,比如: x y / y -> x / z z 这里 x 就是 node。 :param node: :return: """ x = node y = x.right x.right = y.left if y.left: y.left.parent = x y.parent = x.parent if x.parent is None: self.root = y elif x.parent.left == x: x.parent.left = y else: x.parent.right = y y.left = x x.parent = y def _right_rotate_(self, node): """ 节点右旋转,比如: x y / y -> x / z z :param node: :return: """ x = node y = x.left x.left = y.right if y.right: y.right.parent = x y.parent = x.parent if x.parent is None: self.root = y elif x.parent.left == x: x.parent.left = y else: x.parent.right = y y.right = x x.parent = y def _leftright_rotate_(self, node): """ 左右双旋转 :param node: :return: """ x = node y = x.left self._left_rotate_(y) self._right_rotate_(x) def _rightleft_rotate_(self, node): """ 右左双旋转 :param node: :return: """ x = node y = x.right self._right_rotate_(y) self._left_rotate_(x) def _transplant_(self, node, f_node): if node.parent is None: self.root = f_node elif node == node.parent.left: node.parent.left = f_node else: node.parent.right = f_node if f_node: f_node.parent = node.parent def _insert_fixup_(self, node): """ 每次插入节点后确保红黑树性质不被破坏 :param node: :return: """ while node.parent and node.parent.is_red(): g = node.get_grandparent() u = node.get_uncle() if u.is_red(): node.parent.color = ‘black‘ u.color = ‘black‘ g.color = ‘red‘ node = g elif node == node.parent.left: node.color = ‘black‘ g.color = ‘red‘ self._rightleft_rotate_(g) node = node.parent else: node.parent.color = ‘black‘ g.color = ‘red‘ self._left_rotate_(g) self.root.color = ‘black‘ def _remove_fixup_(self, node): """ 删除一类节点后确保红黑树性质不被破坏 删除的维护代码很复杂,因为会导致红黑树性质被破坏的情况有 4 种 1.删除一个黑节点,其有 1 个红色孩子(左或右) 2.删除一个黑节点,其有 2 个红色孩子 3.删除一个黑色叶节点,导致破坏性质 5 :对于每个节点,从该节点到其所有叶节点的简单路径上,均包含相同数目的黑色节点。 4.删除一个红节点,其替换节点颜色为黑色(因为红节点必定有两个黑色子节点,所以如果替换节点也为黑色,替换会导致性质 5 被破坏) :param node: :return: """ # 情况 1 时,不进入循环,直接将其节点染为黑色即可 while node != self.root and not node.is_red(): # 如果当前维护节点不是根节点且颜色为黑色则进入循环 if node == node.parent.left: # 如果维护节点是左孩子 s = node.parent.right # 获取维护节点的兄弟节点 if s.is_red(): # 如果其颜色为红色则将其颜色设置为黑色,父节点颜色设置为红色(情况 2) s.color = ‘black‘ node.parent.color = ‘red‘ self._left_rotate_(node.parent) s = node.parent.right if not s.left.is_red() and not s.right.is_red(): s.color = ‘red‘ node = node.parent elif not s.right.is_red(): s.left.color = ‘black‘ s.color = ‘red‘ self._right_rotate_(s) s = node.parent.right s.color = node.parent.color node.parent.color = ‘black‘ s.right.color = ‘black‘ self._left_rotate_(node.parent) node = self.root else: # 和上面基本一样只是操作相反 s = node.parent.left if s.is_red(): s.color = ‘black‘ node.parent.color = ‘red‘ self._right_rotate_(node.parent) s = node.parent.left if not s.left.is_red() and not s.right.is_red(): s.color = ‘red‘ node = node.parent elif not s.left.is_red(): s.right.color = ‘black‘ s.color = ‘red‘ self._left_rotate_(s) s = node.parent.left s.color = node.parent.color node.parent.color = ‘black‘ s.left.color = ‘black‘ self._right_rotate_(node.parent) node = self.root node.color = ‘black‘ def insert(self, value): """ 插入节点,和二叉树的插入操作几乎差不多 :param value: :return: """ q = self._get_node_parent_(value) nn = self.NodePre(q, ‘red‘, value) lleaf = self.NodePre(nn, ‘black‘, null=True) rleaf = self.NodePre(nn, ‘black‘, null=True) if q is None: self.root = nn elif q.value > value: q.left = nn else: q.right = nn nn.left = lleaf nn.right = rleaf self._insert_fixup_(nn) def remove(self, value): """ 删除节点 :param value: :return: """ q = self._get_node_(value) if q is None: raise Exception(‘不存在具有值 %s 的节点!‘ % value) color = q.color if q.left.null: fix_node = q.right self._transplant_(q, q.right) elif q.right.null: fix_node = q.left self._transplant_(q, q.left) else: min_slt = self._find_minimum_node_(q.right) color = min_slt.color fix_node = min_slt.right if min_slt.parent == q: if fix_node: fix_node.parent = min_slt else: self._transplant_(min_slt, min_slt.right) min_slt.right = q.right if min_slt.right: min_slt.right.parent = min_slt self._transplant_(q, min_slt) min_slt.left = q.left if min_slt.left: min_slt.left.parent = min_slt min_slt.color = q.color if color == ‘black‘: self._remove_fixup_(fix_node) def _print_(self, rt): """ 中序遍历 :param rt: :return: """ if not rt.null: self._print_(rt.left) print(rt.value, ‘-‘ * 4, rt.color) self._print_(rt.right) def output(self): """ 输出树中所有节点及颜色 :return: """ self._print_(self.root) if __name__ == ‘__main__‘: rbt = Rbtree() rbt.insert(26) rbt.insert(32) rbt.insert(11) rbt.insert(6) rbt.insert(15) rbt.insert(29) rbt.output() rbt.remove(29) # rbt.output() rbt.remove(32) rbt.output() print(rbt.root.value, ‘-‘ * 4, ‘root‘)
以上是关于python - Rad black Tree的主要内容,如果未能解决你的问题,请参考以下文章
1135. Is It A Red-Black Tree (30)