Python implementa la operación de inserción del árbol rojo-negro

Python implementa la operación de inserción del árbol rojo-negro

El artículo anterior de esta columna presentó qué son los árboles rojo-negros y la rotación y decoloración de los árboles rojo-negros.

Referencia: https://blog.csdn.net/weixin_43790276/article/details/106042360

Este artículo usa Python para implementar la operación de inserción de árbol rojo-negro.

Primero enumere las 5 características del árbol rojo-negro:

1. El nodo es rojo o negro.

2. El nodo raíz es negro.

3. Todos los nodos hoja son nodos vacíos negros. (Los nodos hoja son nodos NIL o nodos NULL)

4. Los dos nodos secundarios de cada nodo rojo son nodos negros. (No puede haber dos nodos rojos consecutivos en todas las rutas desde cada nodo hoja hasta la raíz)

5. Todas las rutas desde cualquier nodo a cada uno de sus nodos hoja contienen el mismo número de nodos negros.

Uno, preparación de código

El árbol rojo-negro es un árbol de búsqueda binario especial, así que primero escriba el código del árbol de búsqueda binario, esta parte no se presentará en detalle y se usará directamente más adelante.

# 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. Se define una clase de nodo RBNode, que se utiliza para crear un nuevo nodo y agregarlo al árbol rojo-negro El color del atributo de color del nodo se define en el nodo.

El color predeterminado es rojo, es decir, el nodo insertado predeterminado es un nodo rojo, lo que puede reducir la posibilidad de destruir las características del árbol rojo-negro. Independientemente del color del nuevo nodo, la característica 3 no se puede destruir y las características 1, 2 y 4 se pueden destruir. Si el nodo insertado es negro, la característica 5 debe destruirse y se necesitan ajustes Si el nodo insertado es rojo, la característica 5 no debe destruirse.

2. Se define la clase de árbol rojo-negro RBBinaryTree. El método show_tree () de imprimir el árbol rojo-negro de acuerdo con la estructura del árbol se implementa en la clase, y el color correspondiente se imprime al imprimir el valor de acuerdo con el color del nodo del árbol rojo-negro. Hay dos métodos de inserción de árbol de búsqueda binaria: inserción (raíz, valor) y métodos de búsqueda, búsqueda (raíz, datos).

En segundo lugar, tenga en cuenta el método de rotación del árbol rojo-negro.

La rotación del árbol rojo-negro se divide en zurdos y diestros.

1. La mano izquierda del árbol rojo-negro

Zurdo: tome un nodo como pivote (nodo de rotación), su nodo hijo derecho se convierte en el nodo padre del nodo de rotación, el nodo hijo izquierdo del nodo hijo derecho se convierte en el nodo hijo derecho del nodo de rotación y el izquierdo El nodo hijo del nodo de rotación permanece sin cambios. El nodo hijo izquierdo del nodo hijo derecho es equivalente a "desconectarse" del nodo hijo derecho y volver a conectarse al nodo giratorio.

    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 (nodo): use el nodo como el nodo giratorio para realizar la operación de rotación a la izquierda en el árbol rojo-negro.

El código para zurdos se implementa en tres pasos:

1. Cambie el nodo hijo izquierdo del nodo hijo derecho del nodo de rotación por el nodo hijo derecho del nodo de rotación.

2. Cambie el nodo de rotación al nodo hijo izquierdo del nodo hijo derecho.

3. Reemplace el nodo secundario derecho con la posición del nodo de rotación como nodo secundario del nodo principal del nodo de rotación.

Ahora utilice primero el método de inserción del árbol de búsqueda binaria para generar un árbol de búsqueda binario.

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()

resultado de la operación:

La estructura del árbol de búsqueda binaria después de insertar los datos es como se muestra en la figura a continuación, porque los nodos son todos rojos por defecto, por lo que ahora los nodos son todos nodos rojos. Esto es solo para mostrar la función para zurdos. Después de implementar el método de inserción del árbol rojo-negro, se puede generar un árbol rojo-negro normal. (En aras de la brevedad en este artículo, los nodos NIL o NULL se ignoran en el diagrama de estructura)

Por ejemplo, tomando el nodo 77 como el nodo giratorio, el árbol de búsqueda binaria se gira a la izquierda.

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

resultado de la operación:

La estructura del árbol de búsqueda binaria para zurdos es la siguiente:

2. Rotación derecha del árbol rojo-negro

Rotación derecha: tome un nodo como punto de apoyo (nodo de rotación), su nodo hijo izquierdo se convierte en el nodo padre del nodo de rotación, el nodo hijo derecho del nodo hijo izquierdo se convierte en el nodo hijo izquierdo del nodo de rotación y el hijo derecho El nodo del nodo de rotación permanece sin cambios. El nodo hijo derecho del nodo hijo izquierdo es equivalente a "desconectarse" del nodo hijo izquierdo y volver a conectarse al nodo giratorio.

    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 (nodo): rota a la derecha el árbol rojo-negro con el nodo como nodo giratorio.

El código para diestros se implementa en tres pasos:

1. Cambie el nodo hijo derecho del nodo hijo izquierdo del nodo de rotación por el nodo hijo izquierdo del nodo de rotación.

2. Cambie el nodo de rotación al nodo hijo derecho del nodo hijo izquierdo.

3. Reemplace el nodo secundario izquierdo con la posición del nodo de rotación como nodo secundario del nodo principal del nodo de rotación.

Usando el nodo 80 como un nodo de rotación, gire a la derecha el árbol de búsqueda binario después de la rotación a la izquierda en el paso anterior. Los zurdos y los diestros son mutuamente inversos, y después de ser diestros, el árbol de búsqueda binaria vuelve a su estructura original.

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

En tercer lugar, el método para realizar el cambio de color del árbol rojo-negro.

Decoloración: cambia el color del nodo de rojo a negro o de negro a rojo.

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

change_color (nodo): modifica el color del nodo del nodo. El rojo se vuelve negro, el negro se vuelve rojo.

Por ejemplo, modifique los colores del nodo 10 y del nodo 50.

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

resultado de la operación:

La estructura del árbol de búsqueda binaria después del cambio de color es la siguiente.

Cuarto, para lograr el método de inserción del árbol rojo-negro

Un árbol rojo-negro cumple con las 5 características al principio, después de insertar un nuevo nodo, si las características se destruyen, se deben hacer ajustes para que el árbol rojo-negro vuelva a cumplir con las 5 características.

Este proceso se puede descomponer en dos pasos principales. El primer paso es insertar el nodo en la posición correspondiente de acuerdo con el árbol de búsqueda binaria. Aquí puede llamar directamente al método insert () implementado. El segundo paso es determinar si las características del árbol rojo-negro están dañadas. Si está dañado, utilice la rotación y la decoloración para ajustar el árbol rojo-negro.

Para facilitar la comprensión, primero afirme algunos términos que deben usarse:

Nodo de factor: Debido al cambio de este nodo, la estructura del árbol rojo-negro ha cambiado, que está representada por F (factor_node).

Nodo padre: El nodo padre del nodo de factor, representado por P (parent_node).

Nodo abuelo: El nodo padre del nodo padre del nodo factor, representado por G (grandparent_node).

Nodo tío: el nodo hermano del nodo padre del nodo factor, representado por U (uncle_node).

Después de insertar un nuevo nodo, si es necesario ajustar el árbol rojo-negro y cómo ajustarlo, se dividen en las siguientes situaciones:

1. Si el árbol rojo-negro es un árbol vacío, agregue el nuevo nodo a la posición del nodo raíz y modifique el color del nodo a negro.

2. Si el nodo principal del nuevo nodo es un nodo negro, no se requiere ningún ajuste después de insertar el nuevo nodo.

3. Si el nodo padre del nuevo nodo es un nodo rojo (no satisface la característica 4), se divide en dos categorías según el color del nodo tío.

3.1 El nodo tío es negro, el nodo tío es negro incluye la situación de que el nodo tío está vacío, porque los nodos vacíos (nodos hoja) del árbol rojo-negro deben ser negros.

Cuando el nodo del tío es negro, se puede dividir en cuatro situaciones según la relación estructural del nodo.

3.1.1 El nuevo nodo es el nodo hijo izquierdo del nodo padre, y el nodo padre es también el nodo hijo izquierdo del nodo abuelo (estructura izquierda-izquierda). Gire el nodo principal de rojo a negro y el nodo abuelo negro a rojo, y luego use el nodo abuelo como el nodo giratorio para rotar hacia la derecha.

Hay dos puntos a tener en cuenta aquí:

(1) Otro nodo hijo del nodo padre del nuevo nodo debe ser un nodo hoja. Debido a que el árbol rojo-negro satisface las 5 características antes de insertar el nuevo nodo, suponga que el nodo padre tiene un nodo hijo no vacío. Si este nodo es un nodo rojo, no satisface la característica 4, y si este nodo es negro nodo, no satisface la característica 5.

(2) Al insertar un nuevo nodo, si el nodo padre del nuevo nodo es rojo y el nodo abuelo es negro, entonces el nodo tío no debe ser un nodo negro no vacío, ya sea un nodo hoja o un nodo rojo. Debido a que el árbol rojo-negro satisface las 5 características antes de insertar el nuevo nodo, si el nodo tío es un nodo negro no vacío, el árbol rojo-negro no satisface la característica 5.

En el siguiente 3.2, cuando el nodo del tío es un nodo rojo, después del primer ajuste, es posible que el ajuste no se complete. El nodo abuelo se convierte en el nuevo nodo del factor. Puede parecer que el nodo del factor F es rojo, el nodo padre P es rojo, el caso en el que el nodo abuelo G es negro y el nodo tío U es negro. Por lo tanto, este estado es en realidad un estado intermedio generado durante el proceso de ajuste.En 3.1, el método de procesamiento se da primero, y después de la introducción del nodo tío como el nodo rojo, se pueden conectar entre sí.

3.1.2 El nuevo nodo es el nodo hijo derecho del nodo padre y el nodo padre es el nodo hijo izquierdo del nodo abuelo (estructura izquierda y derecha). Primero, tome el nodo padre como el nodo de rotación para rotar a la izquierda, y luego se convertirá en la estructura de 3.1.1, y luego procese en la forma de 3.1.1.

3.1.3 El nuevo nodo es el nodo hijo derecho del nodo padre, y el nodo padre también es el nodo hijo derecho del nodo abuelo (estructura derecha-derecha). Gire el nodo principal de rojo a negro y el nodo abuelo negro a rojo, y luego use el nodo abuelo como el nodo giratorio para rotar a la izquierda.

3.1.4 El nuevo nodo es el nodo hijo izquierdo del nodo padre y el nodo padre es el nodo hijo derecho del nodo abuelo (estructura derecha-izquierda). Primero tome el nodo padre como el nodo de rotación para rotar a la derecha, y luego se convertirá en la estructura de 3.1.3, y luego trátelo en la forma de 3.1.3.

3.2 El nodo tío es rojo, en este caso, el nodo padre y el nodo tío son de rojo a negro y el nodo abuelo es de negro a rojo.

Después de que el nodo abuelo cambia de negro a rojo, debido a que no conoce el color del nodo padre del nodo abuelo, aún debe juzgar, tomar el nodo abuelo como el nuevo nodo de factor e ingresar de forma recursiva el siguiente ajuste, que se puede dividir en las siguientes cuatro situaciones.

3.2.1 Si el nodo abuelo es el nodo raíz (no satisface la característica 1), vuelva a poner el nodo abuelo en negro y el ajuste finaliza.

3.2.2 Si su nodo padre es negro, no es necesario volver a ajustarlo.

3.2.3 Si el nodo padre es rojo y el nodo tío es negro, se cumple la situación en 3.1 anterior, y 3.1 se llama de forma recursiva.

3.2.4 Si el nodo padre es rojo y el nodo tío también es rojo, está en línea con la situación actual de 3.2, y el proceso de 3.2 se realiza de forma recursiva. Si el nuevo nodo de factor aún cumple la condición de 3.2 después de que se completa el procesamiento, la recursividad continúa hasta que se sale del bucle.

Según el análisis anterior, el código se implementa de la siguiente manera:

    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 (valor): Operación de inserción de árbol rojo-negro, analiza todas las operaciones de inserción y el método de procesamiento de cada caso, la implementación del código es relativamente simple.

Los datos desde el principio se insertan en secuencia utilizando el método de inserción de árbol rojo-negro.

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()

Los resultados de la operación son los siguientes:

La estructura del árbol rojo-negro obtenida es la siguiente:

Dado que hay muchos casos de operación de inserción, al observar el análisis de la operación de inserción, primero debemos comprender las operaciones de rotación y cambio de color.

Después de implementar el código de árbol rojo-negro, se puede ver que cada vez que se inserta un nuevo nodo, el árbol rojo-negro cumple con las cinco características, y algunos árboles rojo-negro no necesariamente se agregan nodo por nodo.

Cinco, el código completo

# 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()

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43790276/article/details/106456969
Recomendado
Clasificación