Python implémente l'opération d'insertion de l'arbre rouge-noir

Python implémente l'opération d'insertion de l'arbre rouge-noir

L'article précédent de cette colonne présentait ce que sont les arbres rouge-noir, ainsi que la rotation et la décoloration des arbres rouge-noir.

Référence: https://blog.csdn.net/weixin_43790276/article/details/106042360

Cet article utilise Python pour implémenter l'opération d'insertion d'arbre rouge-noir.

Commencez par lister les 5 caractéristiques de l'arbre rouge-noir:

1. Le nœud est rouge ou noir.

2. Le nœud racine est noir.

3. Tous les nœuds feuilles sont des nœuds vides noirs. (Les nœuds feuilles sont des nœuds NIL ou des nœuds NULL)

4. Les deux nœuds enfants de chaque nœud rouge sont des nœuds noirs. (Il ne peut pas y avoir deux nœuds rouges consécutifs sur tous les chemins de chaque nœud feuille à la racine)

5. Tous les chemins de n'importe quel nœud vers chacun de ses nœuds feuilles contiennent le même nombre de nœuds noirs.

Premièrement, la préparation du code

L'arbre rouge-noir est un arbre de recherche binaire spécial, donc écrivez d'abord le code de l'arbre de recherche binaire. Cette partie ne sera pas présentée en détail, et elle sera utilisée directement plus tard.

# coding=utf-8
class RBNode(object):
    """节点类"""
    def __init__(self, data, left_child=None, right_child=None, color='red'):
        self.data = data
        self.parent = None
        self.left_child = left_child
        self.right_child = right_child
        self.color = color


class RBBinaryTree(object):
    """红黑树类"""
    def __init__(self):
        self.__root = None
        self.prefix_branch = '├'
        self.prefix_trunk = '|'
        self.prefix_leaf = '└'
        self.prefix_empty = ''
        self.prefix_left = '─L─'
        self.prefix_right = '─R─'

    def is_empty(self):
        return not self.__root

    @property
    def root(self):
        return self.__root

    @root.setter
    def root(self, value):
        self.__root = value if isinstance(value, RBNode) else RBNode(value)

    def insert(self, root, value):
        """二叉搜索树插入节点-递归"""
        node = value if isinstance(value, RBNode) else RBNode(value)
        if self.is_empty():
            self.root = node
            return
        if root is None:
            root = node
        elif node.data < root.data:
            root.left_child = self.insert(root.left_child, value)
            root.left_child.parent = root
        elif node.data > root.data:
            root.right_child = self.insert(root.right_child, value)
            root.right_child.parent = root
        return root

    def search(self, root, data):
        """二叉搜索树的查询操作"""
        if root is None:
            return
        if root.data == data:
            return root
        elif data < root.data:
            return self.search(root.left_child, data)
        elif data > root.data:
            return self.search(root.right_child, data)

    def show_tree(self):
        if self.is_empty():
            print('空二叉树')
            return
        print('-' * 20)
        print("\033[31m{}\033[0m".format(str(self.root.data))) if self.root.color is 'red' else print(str(self.root.data))
        self.__print_tree(self.__root)
        print('-' * 20)

    def __print_tree(self, node, prefix=None):
        if prefix is None:
            prefix, prefix_left_child = '', ''
        else:
            prefix = prefix.replace(self.prefix_branch, self.prefix_trunk).replace(self.prefix_leaf, self.prefix_empty)
            prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty)
        if self.has_child(node):
            if node.right_child is not None:
                if node.right_child.color is 'red':
                    print(prefix + self.prefix_branch + self.prefix_right + "\033[31m{}\033[0m".format(str(node.right_child.data)))
                else:
                    print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data))
                if self.has_child(node.right_child):
                    self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ')
            else:
                print(prefix + self.prefix_branch + self.prefix_right)
            if node.left_child is not None:
                if node.left_child.color is 'red':
                    print(prefix + self.prefix_leaf + self.prefix_left + "\033[31m{}\033[0m".format(str(node.left_child.data)))
                else:
                    print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data))
                if self.has_child(node.left_child):
                    prefix_left_child += '  '
                    self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child)
            else:
                print(prefix + self.prefix_leaf + self.prefix_left)

    def has_child(self, node):
        return node.left_child is not None or node.right_child is not None

1. Une classe de nœuds RBNode est définie, qui est utilisée pour créer un nouveau nœud et l'ajouter à l'arbre rouge-noir.La couleur d'attribut de couleur du nœud est définie dans le nœud.

La couleur par défaut est le rouge, c'est-à-dire que le nœud inséré par défaut est un nœud rouge, ce qui peut réduire la possibilité de détruire les caractéristiques de l'arbre rouge-noir. Quelle que soit la couleur du nouveau nœud, la fonction 3 ne peut pas être détruite et les fonctions 1, 2 et 4 peuvent être détruites. Si le nœud inséré est noir, la fonction 5 doit être détruite et des ajustements sont nécessaires. Si le nœud inséré est rouge, la fonction 5 ne doit pas être détruite.

2. La classe d'arbre rouge-noir RBBinaryTree est définie. La méthode show_tree () d'impression de l'arbre rouge-noir selon l'arborescence est implémentée dans la classe, et la couleur correspondante est imprimée lors de l'impression de la valeur selon la couleur du nœud de l'arbre rouge-noir. Il existe deux méthodes d'insertion d'arbre de recherche binaire insert (racine, valeur) et recherche de méthodes de recherche (racine, données).

Deuxièmement, réalisez la méthode de rotation de l'arbre rouge-noir

La rotation de l'arbre rouge-noir est divisée en gaucher et droitier.

1. La main gauche de l'arbre rouge-noir

Gaucher: prenez un nœud comme pivot (nœud de rotation), son nœud enfant droit devient le nœud parent du nœud de rotation, le nœud enfant gauche du nœud enfant droit devient le nœud enfant droit du nœud de rotation, et le nœud gauche le nœud enfant du nœud de rotation reste inchangé. Le nœud enfant gauche du nœud enfant droit équivaut à «se déconnecter» du nœud enfant droit et à se reconnecter au nœud en rotation.

    def left_rotate(self, node):
        """红黑树左旋"""
        parent_node, right_node = node.parent, node.right_child
        if not right_node:
            return
        # 1.node是旋转节点,将旋转节点的右子节点的左子节点变为旋转节点的右子节点
        node.right_child = right_node.left_child
        if node.right_child:
            node.right_child.parent = node
        # 2.将旋转节点修改为右子节点的左子节点
        right_node.left_child, node.parent = node, right_node
        # 3.将右子节点替换旋转节点的位置,作为旋转节点父节点的子节点
        if not parent_node:
            self.root = right_node
        else:
            if parent_node.left_child == node:
                parent_node.left_child = right_node
            else:
                parent_node.right_child = right_node
        right_node.parent = parent_node

left_rotate (node): utilisez node comme nœud rotatif pour effectuer une opération de rotation à gauche sur l'arbre rouge-noir.

Le code gaucher est implémenté en trois étapes:

1. Remplacez le nœud enfant gauche du nœud enfant droit du nœud de rotation par le nœud enfant droit du nœud de rotation.

2. Remplacez le nœud de rotation par le nœud enfant gauche du nœud enfant droit.

3. Remplacez le nœud enfant droit par la position du nœud de rotation en tant que nœud enfant du nœud parent du nœud de rotation.

Maintenant, utilisez d'abord la méthode d'insertion d'arbre de recherche binaire pour générer un arbre de recherche binaire.

if __name__ == '__main__':
    tree = RBBinaryTree()
    data = [50, 77, 55, 29, 10, 30, 66, 18, 80, 51, 90]
    for i in data:
        tree.insert(tree.root, i)
    tree.show_tree()

résultat de l'opération:

La structure de l'arborescence de recherche binaire après l'insertion des données est comme indiqué dans la figure ci-dessous, car les nœuds sont tous rouges par défaut, donc maintenant les nœuds sont tous des nœuds rouges. Ceci est juste pour montrer la fonction gaucher. Après que la méthode d'insertion d'arbre rouge-noir soit implémentée plus tard, un arbre rouge-noir normal peut être généré. (Par souci de concision dans cet article, les nœuds NIL ou NULL sont ignorés dans le diagramme de structure)

Par exemple, en prenant le nœud 77 comme nœud rotatif, l'arbre de recherche binaire est tourné vers la gauche.

    node = tree.search(tree.root, 77)
    tree.left_rotate(node)
    tree.show_tree()

résultat de l'opération:

L'arborescence de recherche binaire à gauche est la suivante:

2. Rotation droite de l'arbre rouge-noir

Rotation à droite: prenez un nœud comme point d'appui (nœud de rotation), son nœud enfant gauche devient le nœud parent du nœud de rotation, le nœud enfant droit du nœud enfant gauche devient le nœud enfant gauche du nœud de rotation et l'enfant droit Le nœud du nœud de rotation reste inchangé. Le nœud enfant droit du nœud enfant gauche équivaut à «se déconnecter» du nœud enfant gauche et à se reconnecter au nœud en rotation.

    def right_rotate(self, node):
        """红黑树右旋"""
        parent_node, left_node = node.parent, node.left_child
        if not left_node:
            return
        # 1.node是旋转节点,将旋转节点的左子节点的右子节点变为旋转节点的左子节点
        node.left_child = left_node.right_child
        if node.left_child:
            node.left_child.parent = node
        # 2.将旋转节点修改为左子节点的右子节点
        left_node.right_child, node.parent = node, left_node
        # 3.将左子节点替换旋转节点的位置,作为旋转节点父节点的子节点
        if not parent_node:
            self.root = left_node
        else:
            if parent_node.left_child == node:
                parent_node.left_child = left_node
            else:
                parent_node.right_child = left_node
        left_node.parent = parent_node

right_rotate (node): Faites pivoter à droite l'arbre rouge-noir avec node comme nœud rotatif.

Le code droitier est implémenté en trois étapes:

1. Remplacez le nœud enfant droit du nœud enfant gauche du nœud de rotation par le nœud enfant gauche du nœud de rotation.

2. Remplacez le nœud de rotation par le nœud enfant droit du nœud enfant gauche.

3. Remplacez le nœud enfant gauche par la position du nœud de rotation en tant que nœud enfant du nœud parent du nœud de rotation.

En utilisant le nœud 80 comme nœud de rotation, faites pivoter à droite l'arborescence de recherche binaire après la rotation à gauche à l'étape précédente. Les gauchers et les droitiers sont mutuellement inverses, et après droitier, l'arbre de recherche binaire revient à sa structure d'origine.

    node = tree.search(tree.root, 80)
    tree.right_rotate(node)
    tree.show_tree()

Troisièmement, la méthode pour réaliser le changement de couleur de l'arbre rouge-noir

Décoloration: changez la couleur du nœud du rouge au noir ou du noir au rouge.

    def change_color(self, node):
        """红黑树变色"""
        if node.color is 'red':
            node.color = 'black'
        elif node.color is 'black':
            node.color = 'red'

change_color (node): modifie la couleur du node node. Le rouge devient noir, le noir devient rouge.

Par exemple, modifiez les couleurs du nœud 10 et du nœud 50.

    tree.change_color(tree.search(tree.root, 50))
    tree.change_color(tree.search(tree.root, 10))
    tree.show_tree()

résultat de l'opération:

La structure de l'arborescence de recherche binaire après le changement de couleur est la suivante.

Quatrièmement, pour réaliser la méthode d'insertion de l'arbre rouge-noir

Un arbre rouge-noir satisfait les 5 caractéristiques au début Après avoir inséré un nouveau nœud, si les caractéristiques sont détruites, des ajustements doivent être faits pour que l'arbre rouge-noir réponde aux 5 caractéristiques.

Ce processus peut être décomposé en deux étapes principales. La première étape consiste à insérer le nœud dans la position correspondante selon l'arbre de recherche binaire. Ici, vous pouvez appeler directement la méthode insert () implémentée. La deuxième étape consiste à déterminer si les caractéristiques de l'arbre rouge-noir sont endommagées.S'il est endommagé, utilisez la rotation et la décoloration pour ajuster l'arbre rouge-noir.

Afin de faciliter la compréhension, commencez par affirmer quelques termes à utiliser:

Noeud de facteur: En raison du changement de ce noeud, la structure de l'arbre rouge-noir a changé, ce qui est représenté par F (factor_node).

Noeud parent: Le noeud parent du noeud facteur, représenté par P (noeud_parent).

Nœud grand-parent: Le nœud parent du nœud parent du nœud facteur, représenté par G (grandparent_node).

Oncle node: le nœud frère du nœud parent du nœud factor, représenté par U (uncle_node).

Après avoir inséré un nouveau nœud, si l'arbre rouge-noir doit être ajusté et comment l'ajuster, sont divisés dans les situations suivantes:

1. Si l'arbre rouge-noir est un arbre vide, ajoutez le nouveau nœud à la position du nœud racine et modifiez la couleur du nœud en noir.

2. Si le nœud parent du nouveau nœud est un nœud noir, aucun ajustement n'est requis après l'insertion du nouveau nœud.

3. Si le nœud parent du nouveau nœud est un nœud rouge (ne satisfaisant pas la caractéristique 4), il est divisé en deux catégories selon la couleur du nœud oncle.

3.1 Le nœud oncle est noir, le nœud oncle est noir inclut la situation où le nœud oncle est vide, car les nœuds vides (nœuds feuilles) de l'arbre rouge-noir doivent être noirs.

Lorsque le nœud oncle est noir, il peut être divisé en quatre situations selon la relation structurelle du nœud.

3.1.1 Le nouveau nœud est le nœud enfant gauche du nœud parent, et le nœud parent est également le nœud enfant gauche du nœud grand-parent (structure gauche-gauche). Tournez le nœud parent du rouge au noir et le nœud grand-père du noir au rouge, puis utilisez le nœud grand-père comme nœud rotatif pour pivoter vers la droite.

Il y a deux points à noter ici:

(1). Un autre nœud enfant du nœud parent du nouveau nœud doit être un nœud feuille. Étant donné que l'arbre rouge-noir satisfait les 5 caractéristiques avant d'insérer le nouveau nœud, supposons que le nœud parent ait un nœud enfant non vide. Si ce nœud est un nœud rouge, il ne satisfait pas la caractéristique 4, et si ce nœud est un nœud noir noeud, il ne satisfait pas la caractéristique 5.

(2). Lors de l'insertion d'un nouveau nœud, si le nœud parent du nouveau nœud est rouge et le nœud grand-parent est noir, alors le nœud oncle ne doit pas être un nœud noir non vide, ni un nœud feuille, ni un nœud rouge. Parce que l'arbre rouge-noir satisfait les 5 caractéristiques avant d'insérer le nouveau nœud, si le nœud oncle est un nœud noir non vide, l'arbre rouge-noir ne satisfait pas la caractéristique 5.

Dans la section 3.2 suivante, lorsque le nœud oncle est un nœud rouge, après le premier ajustement, l'ajustement peut ne pas être terminé. Le nœud grand-père devient le nouveau nœud facteur. Il peut sembler que le nœud facteur F est rouge, le nœud parent P est rouge, Le cas où le nœud grand-père G est noir et le nœud oncle U est noir. Par conséquent, cet état est en fait un état intermédiaire généré pendant le processus d'ajustement.En 3.1, la méthode de traitement est donnée en premier, et après l'introduction du nœud oncle en tant que nœud rouge, il peut être connecté ensemble.

3.1.2 Le nouveau nœud est le nœud enfant droit du nœud parent, et le nœud parent est le nœud enfant gauche du nœud grand-parent (structure gauche et droite). Tout d'abord, prenez le nœud parent comme nœud de rotation pour tourner à gauche, puis il deviendra la structure de 3.1.1, puis traitez-le à la manière de 3.1.1.

3.1.3 Le nouveau nœud est le nœud enfant droit du nœud parent, et le nœud parent est également le nœud enfant droit du nœud grand-parent (structure droite-droite). Tournez le nœud parent du rouge au noir et le nœud grand-père du noir au rouge, puis utilisez le nœud grand-père comme nœud rotatif pour effectuer une rotation vers la gauche.

3.1.4 Le nouveau nœud est le nœud enfant gauche du nœud parent, et le nœud parent est le nœud enfant droit du nœud grand-parent (structure droite-gauche). Prenez d'abord le nœud parent comme nœud de rotation pour tourner à droite, puis il deviendra la structure de 3.1.3, puis traitez-le à la manière de 3.1.3.

3.2 Le nœud oncle est rouge Dans ce cas, le nœud parent et le nœud oncle sont rouge à noir et le nœud grand-père est noir à rouge.

Une fois que le nœud grand-père est passé du noir au rouge, parce que vous ne connaissez pas la couleur du nœud parent du nœud grand-père, vous devez toujours juger, prendre le nœud grand-père comme nouveau nœud de facteur et entrer récursivement le prochain ajustement, qui peut être divisé en quatre situations.

3.2.1 Si le nœud grand-père est le nœud racine (ne satisfaisant pas la caractéristique 1), ramenez le nœud grand-père au noir et l'ajustement se termine.

3.2.2 Si son nœud parent est noir, il n'est pas nécessaire de l'ajuster à nouveau.

3.2.3 Si le nœud parent est rouge et le nœud oncle est noir, la situation en 3.1 ci-dessus est remplie, et 3.1 est appelé récursivement.

3.2.4 Si le nœud parent est rouge et le nœud oncle est également rouge, cela correspond à la situation actuelle de 3.2, et le processus de 3.2 est effectué de manière récursive. Si le nouveau nœud de facteur remplit toujours la condition de 3,2 une fois le traitement terminé, la récursivité se poursuit jusqu'à ce que la boucle soit sortie.

Selon l'analyse ci-dessus, le code est implémenté comme suit:

    def rb_insert(self, value):
        """红黑树插入"""
        node = value if isinstance(value, RBNode) else RBNode(value)
        if self.search(self.root, node.data):
            return
        if self.is_empty():
            node.color = 'black'
            self.root = node
            return
        self.insert(self.root, node)
        factor_node = node
        while True:
            parent_node = factor_node.parent
            if parent_node.color is 'red':
                grandparent_node = parent_node.parent
                if parent_node is grandparent_node.left_child:
                    uncle_node = grandparent_node.right_child
                else:
                    uncle_node = grandparent_node.left_child
                # 如果父节点为红节点且叔节点为黑节点
                if uncle_node is None or uncle_node and uncle_node.color is 'black':
                    if parent_node == grandparent_node.left_child:
                        # 先左旋为左左结果,然后父节点和祖父节点变色,再右旋
                        if factor_node == parent_node.right_child:
                            self.left_rotate(parent_node)
                            self.change_color(factor_node)
                        else:
                            self.change_color(parent_node)
                        self.change_color(grandparent_node)
                        self.right_rotate(grandparent_node)
                    elif parent_node == grandparent_node.right_child:
                        # 先右旋为右右结构,然后父节点和祖父节点变色,再左旋
                        if factor_node == parent_node.left_child:
                            self.right_rotate(parent_node)
                            self.change_color(factor_node)
                        else:
                            self.change_color(parent_node)
                        self.change_color(grandparent_node)
                        self.left_rotate(grandparent_node)
                    break
                # 如果父节点为红节点且叔节点也为红节点
                elif uncle_node and uncle_node.color is 'red':
                    # 父节点和叔节点变色,祖父节点变色(祖父节点是根节点除外)
                    self.change_color(parent_node)
                    self.change_color(uncle_node)
                    if grandparent_node != self.root:
                        self.change_color(grandparent_node)
                        # 祖父节点变成红节点后,将祖父节点作为新的因素节点,判断其父节点,避免不满足特性4
                        factor_node = grandparent_node
            else:
                break

rb_insert (valeur): Opération d'insertion d'arbre rouge-noir, analyse toutes les opérations d'insertion et la méthode de traitement de chaque cas, l'implémentation du code est relativement simple.

Les données du début sont insérées en séquence à l'aide de la méthode d'insertion d'arbre rouge-noir.

if __name__ == '__main__':
    tree = RBBinaryTree()
    data = [50, 77, 55, 29, 10, 30, 66, 18, 80, 51, 90]
    for i in data:
        # tree.insert(tree.root, i)
        tree.rb_insert(i)
    tree.show_tree()

Les résultats de l'opération sont les suivants:

La structure arborescente rouge-noire obtenue est la suivante:

Comme il existe de nombreux cas d'opération d'insertion, lorsque nous examinons l'analyse de l'opération d'insertion, nous devons d'abord comprendre les opérations de rotation et de changement de couleur.

Après avoir implémenté le code de l'arbre rouge-noir, on peut voir qu'à chaque fois qu'un nouveau nœud est inséré, l'arbre rouge-noir répond aux cinq caractéristiques, et certains arbres rouge-noir ne sont pas nécessairement ajoutés nœud par nœud.

Cinq, le code complet

# coding=utf-8
class RBNode(object):
    """节点类"""
    def __init__(self, data, left_child=None, right_child=None, color='red'):
        self.data = data
        self.parent = None
        self.left_child = left_child
        self.right_child = right_child
        self.color = color


class RBBinaryTree(object):
    """红黑树类"""
    def __init__(self):
        self.__root = None
        self.prefix_branch = '├'
        self.prefix_trunk = '|'
        self.prefix_leaf = '└'
        self.prefix_empty = ''
        self.prefix_left = '─L─'
        self.prefix_right = '─R─'

    def is_empty(self):
        return not self.__root

    @property
    def root(self):
        return self.__root

    @root.setter
    def root(self, value):
        self.__root = value if isinstance(value, RBNode) else RBNode(value)

    def left_rotate(self, node):
        """红黑树左旋"""
        parent_node, right_node = node.parent, node.right_child
        if not right_node:
            return
        # 1.node是旋转节点,将旋转节点的右子节点的左子节点变为旋转节点的右子节点
        node.right_child = right_node.left_child
        if node.right_child:
            node.right_child.parent = node
        # 2.将旋转节点修改为右子节点的左子节点
        right_node.left_child, node.parent = node, right_node
        # 3.将右子节点替换旋转节点的位置,作为旋转节点父节点的子节点
        if not parent_node:
            self.root = right_node
        else:
            if parent_node.left_child == node:
                parent_node.left_child = right_node
            else:
                parent_node.right_child = right_node
        right_node.parent = parent_node

    def right_rotate(self, node):
        """红黑树右旋"""
        parent_node, left_node = node.parent, node.left_child
        if not left_node:
            return
        # 1.node是旋转节点,将旋转节点的左子节点的右子节点变为旋转节点的左子节点
        node.left_child = left_node.right_child
        if node.left_child:
            node.left_child.parent = node
        # 2.将旋转节点修改为左子节点的右子节点
        left_node.right_child, node.parent = node, left_node
        # 3.将左子节点替换旋转节点的位置,作为旋转节点父节点的子节点
        if not parent_node:
            self.root = left_node
        else:
            if parent_node.left_child == node:
                parent_node.left_child = left_node
            else:
                parent_node.right_child = left_node
        left_node.parent = parent_node

    def change_color(self, node):
        """红黑树变色"""
        if node.color is 'red':
            node.color = 'black'
        elif node.color is 'black':
            node.color = 'red'

    def rb_insert(self, value):
        """红黑树插入"""
        node = value if isinstance(value, RBNode) else RBNode(value)
        if self.search(self.root, node.data):
            return
        if self.is_empty():
            node.color = 'black'
            self.root = node
            return
        self.insert(self.root, node)
        factor_node = node
        while True:
            parent_node = factor_node.parent
            if parent_node.color is 'red':
                grandparent_node = parent_node.parent
                if parent_node is grandparent_node.left_child:
                    uncle_node = grandparent_node.right_child
                else:
                    uncle_node = grandparent_node.left_child
                # 如果父节点为红节点且叔节点为黑节点
                if uncle_node is None or uncle_node and uncle_node.color is 'black':
                    if parent_node == grandparent_node.left_child:
                        # 先左旋为左左结果,然后父节点和祖父节点变色,再右旋
                        if factor_node == parent_node.right_child:
                            self.left_rotate(parent_node)
                            self.change_color(factor_node)
                        else:
                            self.change_color(parent_node)
                        self.change_color(grandparent_node)
                        self.right_rotate(grandparent_node)
                    elif parent_node == grandparent_node.right_child:
                        # 先右旋为右右结构,然后父节点和祖父节点变色,再左旋
                        if factor_node == parent_node.left_child:
                            self.right_rotate(parent_node)
                            self.change_color(factor_node)
                        else:
                            self.change_color(parent_node)
                        self.change_color(grandparent_node)
                        self.left_rotate(grandparent_node)
                    break
                # 如果父节点为红节点且叔节点也为红节点
                elif uncle_node and uncle_node.color is 'red':
                    # 父节点和叔节点变色,祖父节点变色(祖父节点是根节点除外)
                    self.change_color(parent_node)
                    self.change_color(uncle_node)
                    if grandparent_node != self.root:
                        self.change_color(grandparent_node)
                        # 祖父节点变成红节点后,将祖父节点作为新的因素节点,判断其父节点,避免不满足特性4
                        factor_node = grandparent_node
            else:
                break

    def insert(self, root, value):
        """二叉搜索树插入节点-递归"""
        node = value if isinstance(value, RBNode) else RBNode(value)
        if self.is_empty():
            self.root = node
            return
        if root is None:
            root = node
        elif node.data < root.data:
            root.left_child = self.insert(root.left_child, value)
            root.left_child.parent = root
        elif node.data > root.data:
            root.right_child = self.insert(root.right_child, value)
            root.right_child.parent = root
        return root

    def search(self, root, data):
        """二叉搜索树的查询操作"""
        if root is None:
            return
        if root.data == data:
            return root
        elif data < root.data:
            return self.search(root.left_child, data)
        elif data > root.data:
            return self.search(root.right_child, data)

    def show_tree(self):
        if self.is_empty():
            print('空二叉树')
            return
        print('-' * 20)
        print("\033[31m{}\033[0m".format(str(self.root.data))) if self.root.color is 'red' else print(str(self.root.data))
        self.__print_tree(self.__root)
        print('-' * 20)

    def __print_tree(self, node, prefix=None):
        if prefix is None:
            prefix, prefix_left_child = '', ''
        else:
            prefix = prefix.replace(self.prefix_branch, self.prefix_trunk).replace(self.prefix_leaf, self.prefix_empty)
            prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty)
        if self.has_child(node):
            if node.right_child is not None:
                if node.right_child.color is 'red':
                    print(prefix + self.prefix_branch + self.prefix_right + "\033[31m{}\033[0m".format(str(node.right_child.data)))
                else:
                    print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data))
                if self.has_child(node.right_child):
                    self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ')
            else:
                print(prefix + self.prefix_branch + self.prefix_right)
            if node.left_child is not None:
                if node.left_child.color is 'red':
                    print(prefix + self.prefix_leaf + self.prefix_left + "\033[31m{}\033[0m".format(str(node.left_child.data)))
                else:
                    print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data))
                if self.has_child(node.left_child):
                    prefix_left_child += '  '
                    self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child)
            else:
                print(prefix + self.prefix_leaf + self.prefix_left)

    def has_child(self, node):
        return node.left_child is not None or node.right_child is not None


if __name__ == '__main__':
    tree = RBBinaryTree()
    data = [50, 77, 55, 29, 10, 30, 66, 18, 80, 51, 90]
    for i in data:
        # tree.insert(tree.root, i)
        tree.rb_insert(i)
    tree.show_tree()

    # node = tree.search(tree.root, 77)
    # tree.left_rotate(node)
    # tree.show_tree()

    # node = tree.search(tree.root, 80)
    # tree.right_rotate(node)
    # tree.show_tree()

    # tree.change_color(tree.search(tree.root, 50))
    # tree.change_color(tree.search(tree.root, 10))
    # tree.show_tree()

 

 

Je suppose que tu aimes

Origine blog.csdn.net/weixin_43790276/article/details/106456969
conseillé
Classement