Рубрики
Без рубрики

Строительство красно-черного двоичного дерева в Python

Создание пост-построения красно-черного двоичного дерева в Python впервые появилось на QVault. Красно-черное дерево … Tagged с Python, Compsci, алгоритмыми, BinaryTree.

Пост Строительство красно-черного двоичного дерева в Python впервые появился на QVault Отказ

Красно-черное дерево – это вид самобалансирующего бинарного поиска. Каждый узел хранит дополнительный бит, который мы будем называть цвет, красный или черный. Цвет гарантирует, что дерево остается примерно сбалансирован во время вставки и удаления. Когда дерево изменено, новое дерево перегружено и перенаправлено, чтобы восстановить свойства окраски, которые ограничат, насколько несбалансирован дерево может стать в худшем случае.

Цель красно-черного дерева – оставаться сбалансированным, что гарантирует, что его общие операции, такие как поиск и удаление, никогда не ухудшаются до хуже, чем O (n * log (n)) .

Извините, что прервало! Я просто хотел упомянуть, что вы должны проверить мой новый бесплатный курс Python, «Структуры данных Big-O». Вы узнаете все, что вам нужно знать, чтобы сокрушить ваши предстоящие интервью по кодированию и сеансам доски.

Начать курс структур данных Python Data

Что такое сбалансированное бинарное дерево?

Поскольку цвета причина добавляются к бинарному дереву, состоит в том, чтобы гарантировать, что он остается сбалансированным, нам нужно понять, как и почему двоичное дерево сбалансировано. Чтобы просто поставить его, ветки сбалансированного дерева различаются по высоте не более 1.

Следующее дерево сбалансировано, потому что между двумя ветвями есть высота 2, а остальное 3, что означает, что они отличаются не более чем 1.

A
   / \
  B C 
 /
D

Следующее дерево несбалансировано, потому что он ветви отличаются по высоте более чем на 1. C Правая сторона имеет высоту 2, в то время как его левая сторона имеет высоту 4).

A
   / \
  B C
 / /
D E  
     /  
    G

Почему мы хотим сбалансированные деревья?

Сбалансированные двоичные валы поиска Убедитесь на Скорость Отказ Скорость операции в бинарном дереве зависит от высоты дерева. Если дерево сбалансировано, то высота только Журнал Из числа узлов, что означает, что дерево будет работать как можно быстрее. Однако, если дерево несбалансировано, например, с одной действительно длинной ветвью, а затем высота, поскольку общее количество узлов, а не журнал.

A
     / 
    B
   /
  C
 /  
D

Свойства красно-черного дерева

В дополнение ко всем свойствам A Двоичное дерево поиска Красно-черное дерево должно иметь следующее:

  1. Каждый узел либо красный, либо черный
  2. Корень черный. Это правило иногда опущено. Поскольку корень всегда может быть изменен с красного до черного, но не обязательно наоборот, это правило мало влияет на анализ.
  3. Все Ниль Узлы листьев черные.
  4. Если узел красный, то обе дети черные.
  5. Все пути из одного узла проходят через то же количество черных узлов, чтобы достичь любого из его потомка Ниль узлы.

Реализация красно-черного дерева в Python

Шаг 1 – класс RBNODE

Наша реализация будет использовать Дерево класс и а Узел класс. Узел будет довольно простым, это просто конструктор.

class RBNode:
    def __init__ (self, val):
        self.red = False
        self.parent = None
        self.val = val
        self.left = None
        self.right = None
Code language: Python (python)

Шаг 2 – RBTree Class

Далее Давайте создадим класс дерева с конструктором.

class RBTree:
    def __init__ (self):
        self.nil = RBNode(0)
        self.nil.red = False
        self.nil.left = None
        self.nil.right = None
        self.root = self.nil`
Code language: Python (python)

Шаг 3 – Вставьте метод

def insert(self, val):
    # Ordinary Binary Search Insertion
    new_node = RBNode(val)
    new_node.parent = None
    new_node.left = self.nil
    new_node.right = self.nil
    new_node.red = True # new node must be red

    parent = None
    current = self.root
    while current != self.nil:
        parent = current
        if new_node.val < current.val:
            current = current.left
        elif new_node.val > current.val:
            current = current.right
        else:
            return

    # Set the parent and insert the new node
    new_node.parent = parent
    if parent == None:
        self.root = new_node
    elif new_node.val < parent.val:
        parent.left = new_node
    else:
        parent.right = new_node

    # Fix the tree
    self.fix_insert(new_node)
Code language: Python (python)

Метод вставки будет выглядеть очень похоже на традиционную бинарный метод вставки дерева. Самое большое значение состоит в том, что после выполнения вставки мы позвоним специальным fix_insert метод. На данный момент просто назовем это, мы реализуем его через минуту.

Шаг 4 – Поверните влево

Нам понадобится некоторые методы вращения в нашем этапе «исправить». Давайте кодируемся сейчас.

# rotate left at node x
def rotate_left(self, x):
    y = x.right
    x.right = y.left
    if y.left != self.nil:
        y.left.parent = x

    y.parent = x.parent
    if x.parent == None:
        self.root = y
    elif x == x.parent.left:
        x.parent.left = y
    else:
        x.parent.right = y
    y.left = x
    x.parent = y
Code language: Python (python)

Шаг 5 – Поверните направо

# rotate right at node x
def rotate_right(self, x):
    y = x.left
    x.left = y.right
    if y.right != self.nil:
        y.right.parent = x

    y.parent = x.parent
    if x.parent == None:
        self.root = y
    elif x == x.parent.right:
        x.parent.right = y
    else:
        x.parent.left = y
    y.right = x
    x.parent = y
Code language: Python (python)

Шаг 6 – исправить вставку

Настоящий хлеб и масло на этом шаге, это то, что делает красно-черное дерево сбалансировано.

def fix_insert(self, new_node):
    while new_node != self.root and new_node.parent.red:
        if new_node.parent == new_node.parent.parent.right:
            u = new_node.parent.parent.left # uncle
            if u.red:

                u.red = False
                new_node.parent.red = False
                new_node.parent.parent.red = True
                new_node = new_node.parent.parent
            else:
                if new_node == new_node.parent.left:
                    new_node = new_node.parent
                    self.rotate_right(new_node)
                new_node.parent.red = False
                new_node.parent.parent.red = True
                self.rotate_left(new_node.parent.parent)
        else:
            u = new_node.parent.parent.right # uncle

            if u.red:
                u.red = False
                new_node.parent.red = False
                new_node.parent.parent.red = True
                new_node = new_node.parent.parent
            else:
                if new_node == new_node.parent.right:
                    new_node = new_node.parent
                    self.rotate_left(new_node)
                new_node.parent.red = False
                new_node.parent.parent.red = True
                self.rotate_right(new_node.parent.parent)
    self.root.red = False
Code language: Python (python)

Полный пример красно-черного дерева в коде

import random

class RBNode:
    def __init__ (self, val):
        self.red = False
        self.parent = None
        self.val = val
        self.left = None
        self.right = None

class RBTree:
    def __init__ (self):
        self.nil = RBNode(0)
        self.nil.red = False
        self.nil.left = None
        self.nil.right = None
        self.root = self.nil

    def insert(self, val):
        # Ordinary Binary Search Insertion
        new_node = RBNode(val)
        new_node.parent = None
        new_node.left = self.nil
        new_node.right = self.nil
        new_node.red = True # new node must be red

        parent = None
        current = self.root
        while current != self.nil:
            parent = current
            if new_node.val < current.val:
                current = current.left
            elif new_node.val > current.val:
                current = current.right
            else:
                return

        # Set the parent and insert the new node
        new_node.parent = parent
        if parent == None:
            self.root = new_node
        elif new_node.val < parent.val:
            parent.left = new_node
        else:
            parent.right = new_node

        # Fix the tree
        self.fix_insert(new_node)

    def fix_insert(self, new_node):
        while new_node != self.root and new_node.parent.red:
            if new_node.parent == new_node.parent.parent.right:
                u = new_node.parent.parent.left # uncle
                if u.red:
                    u.red = False
                    new_node.parent.red = False
                    new_node.parent.parent.red = True
                    new_node = new_node.parent.parent
                else:
                    if new_node == new_node.parent.left:
                        new_node = new_node.parent
                        self.rotate_right(new_node)
                    new_node.parent.red = False
                    new_node.parent.parent.red = True
                    self.rotate_left(new_node.parent.parent)
            else:
                u = new_node.parent.parent.right # uncle

                if u.red:
                    u.red = False
                    new_node.parent.red = False
                    new_node.parent.parent.red = True
                    new_node = new_node.parent.parent
                else:
                    if new_node == new_node.parent.right:
                        new_node = new_node.parent
                        self.rotate_left(new_node)
                    new_node.parent.red = False
                    new_node.parent.parent.red = True
                    self.rotate_right(new_node.parent.parent)
        self.root.red = False

    def exists(self, val):
        curr = self.root
        while curr != self.nil and val != curr.val:
            if val < curr.val:
                curr = curr.left
            else:
                curr = curr.right
        return curr

    # rotate left at node x
    def rotate_left(self, x):
        y = x.right
        x.right = y.left
        if y.left != self.nil:
            y.left.parent = x

        y.parent = x.parent
        if x.parent == None:
            self.root = y
        elif x == x.parent.left:
            x.parent.left = y
        else:
            x.parent.right = y
        y.left = x
        x.parent = y

    # rotate right at node x
    def rotate_right(self, x):
        y = x.left
        x.left = y.right
        if y.right != self.nil:
            y.right.parent = x

        y.parent = x.parent
        if x.parent == None:
            self.root = y
        elif x == x.parent.right:
            x.parent.right = y
        else:
            x.parent.left = y
        y.right = x
        x.parent = y

    def __repr__ (self):
        lines = []
        print_tree(self.root, lines)
        return '\n'.join(lines)

def print_tree(node, lines, level=0):
    if node.val != 0:
        print_tree(node.left, lines, level + 1)
        lines.append('-' * 4 * level + '> ' +
                     str(node.val) + ' ' + ('r' if node.red else 'b'))
        print_tree(node.right, lines, level + 1)

def get_nums(num):
    random.seed(1)
    nums = []
    for _ in range(num):
        nums.append(random.randint(1, num-1))
    return nums

def main():
    tree = RBTree()
    for x in range(1, 51):
        tree.insert(x)
    print(tree)

main()
Code language: Python (python)

Готов к кодированию?

Попробуйте наши курсы кодирования бесплатно

Присоединяйтесь к нашему сообществу

Есть вопросы или обратная связь?

Следуйте и ударили меня в Twitter @q_vault. Если у вас есть какие-либо вопросы или комментарии. Если я допустил ошибку в статье, обязательно дай мне знать Так что я могу получить его исправленным!

Оригинал: “https://dev.to/qvault/building-a-red-black-binary-tree-in-python-208a”