30. Красно – черные деревья. Свойства. Вращение. Высота красно – черного дерева.
Красно-черные деревья представляют собой одну из множества «сбалансированных» схем деревьев поиска, которые гарантируют время выполнения операций над динамическим множеством O(log2n) даже в наихудшем случае.
Красно-черное дерево (red-black tree) — это двоичное дерево поиска, вершины которого разделены на красные (red) и черные (black). Таким образом каждая вершина хранит один дополнительный бит — её цвет.
При этом выполняются определённые требования, которые гарантируют, что глубины любых двух листьев отличаются не более чем в два раза.
Каждая вершина красно-черного дерева имеет поля color (цвет), key (ключ), left (левый ребенок), right (правый ребенок) и p (родитель). Если у вершины отсутствует ребенок или родитель, то соответствующее поле содержит NIL.
Двоичное дерево поиска называется красно-черным, если оно обладает следующими свойствами:
- каждая вершина — либо черная, либо красная ;
- корень дерева является черным;
- каждый лист (NIL) — чёрный ;
- если вершина красная, оба её ребенка чёрные ;
- все пути, идущие вниз от корня к листьям, содержат одинаковое количество чёрных вершин.
Повороты
Операции над деревом поиска Tree_Insert и Tree_Delete, будучи применены к красно-черному дереву с n ключами, выполняются за время O(log2n). Поскольку они изменяют дерево, в результате их работы могут нарушаться красно-черные свойства. Для восстановления этих свойств мы должны изменить цвета некоторых узлов дерева, а также структуру его указателей. Изменения в структуре указателей будут выполняться при помощи поворотов (rotations), которые представляют собой локальные операции в дереве поиска, сохраняющие свойство бинарного дерева поиска. На рис. показаны два типа поворотов — левый и правый (здесь — произвольные поддеревья). При выполнении левого поворота в узлех предполагается, что его правый дочерний узел у не является листом nil [T]. Левый поворот выполняется «вокруг» связи между х и у, делая у новым корнем поддерева, левым дочерним узлом которого становится х, а бывший левый потомок узла у — правым потомком х.
Операции поворота в бинарном дереве поиска
В псевдокоде процедуры Left_Rotate предполагается, что right[х] nil [Т], а родитель корневого узла — nil[T]. Left_Rotate(T, х)
- у
right[x]
Устанавливаем у.
- right[x]
left[y]
Левое поддерево у становится правым поддеревом х
3 if left[y]nil[T] 4 then p[left[y]]
х
- р[у]
р[х]
Перенос родителя х в у
- if p[x] = nil[T]
- then root[T]
у
- else if x = left[p[х]]
9 then left [p[x]] у 10 else right[p[x]]
у
- left[y]
x
x— левый дочерний у
- p[x]
у
31. Добавление вершины в красно – черном дереве.
Сначала выполняется обычная операция включения в двоичное дерево Tree_Insert и новая вершина помечается красным цветом. После этого восстанавливаются RB-свойства, если они нарушены путем перекраски вершин и вращений. Рассмотрим случаи нарушения RB-свойств на примере включения в дерево: При включении х нарушено третьеRB-свойство для вершины 5 (оба сына должны быть черные). Т.е. RB-свойство нарушается, если родитель нового узла красный. Как можно восстановить его: Случай 1: Если родитель красный, то родитель родителя – черный (в силу RB-свойства 2). Если у деда (7) второй сын – у ( дядя нового узла х) тоже красный, то можно перекрасить указанных предков: сделать деда красным, а родителя и дядю – черными. Это не изменит черную высоту дерева и восстановит третье свойство для родителя(5). П
осле перекраски. Т
.е. теперь 5 – черная вершина, которая может иметь и красного и черного сына. Но появился новый красный узел х(7). Теперь нарушено 3-еRB-свойство родителя узла 7 (2), т.к. этот узел тоже красный. К сожалению дядя (14) не красный и перекраску делать нельзя, не нарушив черной высоты. Тогда используем LL – поворот родителя х – (2). Исправлено нарушение 3-го свойства для узла 2, но нарушено для узла 7. С
лучай 3 отличается от случая 2 тем, что х является левым, а не правым сыном своего родителя. В этом случае делаем правый поворот родителя (11). Красную вершину 7, оказавшуюся в корне, окрашиваем в черную, а вершины 2 и 11 – в красные. Это не нарушит RB-свойство 4).
RB_Insert (T, x)
- Tree_Insert (T, x)
- color [x] ← RED
- while x ≠ root [T] and color [p[x]] = RED
- dv if p[x] = left [p[p[x]]]
- then y ← right [p[p[x]]]
- if color [y] = RED
then color [p[x]] ← BLACK случай 1
color [y] ← BLACK случай 1
color [p[p[x]]] ← RED случай 1
x ← p[p[x]] случай 1
- else if x = right [p[x]]
then x ← p[x] случай 2
Left_Rotate (T, x) случай 2
color [p[x]] ← BLACK случай 3
color [p[p[x]]] ← RED случай 3
Right_Rotate (T, p[p[x]]) случай 3
- else (симметричный текст с заменой left ↔ right)
- color [root[T]] ← BLACK
При включении, если выпадает случай 3, выполняется не более одного вращения, и в случае 2 – не более двух вращений.
Источник