Пост Строительство красно-черного двоичного дерева в 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 Двоичное дерево поиска Красно-черное дерево должно иметь следующее:
- Каждый узел либо красный, либо черный
- Корень черный. Это правило иногда опущено. Поскольку корень всегда может быть изменен с красного до черного, но не обязательно наоборот, это правило мало влияет на анализ.
- Все
Ниль
Узлы листьев черные. - Если узел красный, то обе дети черные.
- Все пути из одного узла проходят через то же количество черных узлов, чтобы достичь любого из его потомка
Ниль
узлы.
Реализация красно-черного дерева в 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”