
Красно-черные деревья поиска
Красно-черные деревья - один из способов балансировки деревьев. Название происходит от стандартной раскраски узлов таких деревьев в красный и черный цвета. Цвета узлов используются при балансировке дерева. Во время операций вставки и удаления поддеревья может понадобиться повернуть, чтобы достигнуть сбалансированности дерева. Оценкой как среднего время, так и наихудшего является O(log n).
Теория Красно-черное дерево - это бинарное дерево с следующими свойствами:
Каждый узел покрашен либо в черный, либо в красный цвет.
Листьями объявляются NIL-узлы (т.е. "виртуальные" узлы, наследники узлов, которые обычно называют листьями; на них "указывают" NULL указатели). Листья покрашены в черный цвет.
Если узел красный, то оба его потомка черны.
На всех ветвях дерева, ведущих от его корня к листьям, число черных узлов одинаково.
ВСТАВКА
Чтобы вставить узел, мы сначала ищем в дереве место, куда его следует добавить. Новый узел всегда добавляется как лист, поэтому оба его потомка являются NIL-узлами и предполагаются черными. После вставки красим узел в красный цвет. После этого смотрим на предка и проверяем, не нарушается ли красно-черное свойство. Если необходимо, мы перекрашиваем узел и производим поворот, чтобы сбалансировать дерево.
Рассмотрим ситуацию, когда предок нового узла красный: при этом будет нарушено свойство 3. Достаточно рассмотреть следующие два случая:
Красный предок, красный "дядя": Ситуацию красный-красный иллюстрирует рис. 1. Простое перекрашивание избавляет нас от красно-красного нарушения. После перекраски нужно проверить "дедушку" нового узла (узел B), поскольку он может оказаться красным. Обратите внимание на распространение влияния красного узла на верхние узлы дерева. В самом конце корень мы красим в черный цвет корень дерева. Если он был красным, то при этом увеличивается черная высота дерева.
Красный предок, черный "дядя": На рис. 3.7 представлен другой вариант красно-красного. Здесь узлы может понадобиться вращать, чтобы скорректировать поддеревья. В этом месте алгоритм может остановиться из-за отсутствия красно-красных конфликтов и вершина дерева (узел A) окрашивается в черный цвет.
Каждая корректировка, производимая при вставке узла, заставляет нас подняться в дереве на один шаг. В этом случае до остановки алгоритма будет сделано 1 вращение (2, если узел был правым потомком). Метод удаления аналогичен.
Вращения
{-------------LL------------}
T^.left:=p1^.right;
p1^.right:=T;
P1^.lred:=false;
T:=P1
{-------------LR------------}
P2:=P1^.right; P1^.rred:=false;
P1^.right:=P2^.left;
P2^.left:=P1;
T^.left:=P2^.right;
P2^.right:=T; T:=P2
{------------RR------------}
T^.right:=p1^.left;
p1^.left:=T;
P1^.rred:=false;
T:=P1
{------------RL------------}
P2:=P1^.left; P1^.lred:=false;
P1^.left:=P2^.right;
P2^.right:=P1;
T^.right:=P2^.left;
P2^.left:=T; T:=P2
Поиск вершины
Процедура поиска аналогична поиску в бинарном дереве.
Добавление вершины
Добавление вершины в красно-черное дерево производится за время O(log n).
После добавления вершины выполняются все свойства красно-черного дерева, кроме одного: красная вершина x может иметь красного родителя, и это нарушение единственно. Восстанавливается это свойство очень просто: пока вершина x не корень дерева и имеет красного родителя выполняем следующие действия:
Если дядя вершины x красного цвета, то красим его и отца вершины x в черный цвет, а дедушку вершины x в красный цвет. Далее вершиной x становится дедушка.
Если дядя вершины х черного цвета, то проверяем являются ли вершина x и его отец одинаковыми детьми (т.е. оба ЛЕВЫЕ или ПРАВЫЕ дети). Если не являются одинаковыми детьми, то делаем соответствующие вращение (становятся одинаковыми детьми). Красим отца в черный цвет. Далее делаем соответствующее вращение; Будем полагать, что во всех красно-черных деревьях корень черный и поддерживать это свойство.
Удаление вершины
Как и другие операции, удаление вершины из красно-чёрного дерева требует времени O(log n). Удаление вершины несколько сложнее добавления.
Для начала находим вершину z в дереве, которую требуется удалить. Возможны три случая:
если у вершины z нет детей, для удаления z достаточно поместить NIL в соответствующее поле его родителя (вместо z).
если у z один ребенок, то можно вырезать z, соединив его родителя напрямую с его ребенком.
если у z двое детей, то мы находим следующий (в смысле порядка на ключах) за z элемент y; у него нет левого ребенка. Теперь можно скопировать ключ и дополнительные данные из вершины y в вершину z, а саму вершину y удалить выше описанным способом.
Если была удалена черная вершина, то надо восстановить свойства красно-черного дерева (при удалении красной вершины свойства дерева не нарушаются). Пусть вершина x - ребенок удаленной вершины. Пока вершина x не корень дерева и она чёрная вершина выполняем следующие действия:
если у вершины x брат красного цвета, то делаем ВРАЩЕНИЕ (брат становится родителем отца), при этом брата красим в черный, а отца в красный.
если у вершины x брат чёрного цвета, то
если у брата оба ребенка черные, то красим брата в красный цвет. Теперь вершиной x будет его отец.
если у брата его "одинаковый" ребёнок черного цвета, то красим брата в красный цвет и делаем вращение.
иначе красим брата в цвет отца, отца красим в черный цвет. Делаем вращение и выходим из цикла.
Красно-чёрные деревья являются одними из наиболее активно используемых на практике самобалансирующихся деревьев поиска.
Временная сложность поиска: O(log n) в лучшем случае. Поскольку красно-чёрное дерево, в худшем случае, выше, поиск в нём медленнее, но проигрыш по времени не превышает 39%.
Максимальная длина пути – 2 log N. Операции поиска – за O(log N).