Красно-черное дерево — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Свойства)
Строка 76: Строка 76:
 
Т.к. общее время выполнения каждой из операций порядка высоты дерева ,то все они выполняются за <tex>O(\log{n})</tex>.
 
Т.к. общее время выполнения каждой из операций порядка высоты дерева ,то все они выполняются за <tex>O(\log{n})</tex>.
  
==Ссылки.==
+
== Преимущество красно-чёрных деревьев ==
 +
Одно из основных преимуществ красно-чёрных деревьев заключается в том, что процедуру балансировки практически всегда можно выполнять параллельно с процедурами поиска, т.к. алгоритм поиска не зависит от аттрибута цвета узлов. Вращение поддеревьев не может выполнятся одновременно с поиском,
 +
но при вставке выполняется не более <tex>O(1)</tex> вращений.
 +
 
 +
Красно-чёрные деревья являются наиболее активно используемыми на практике самобалансирующимися деревьями поиска. В частности, ассоциативные контейнеры библиотеки STL (map, set, multiset, multimap) основаны на красно-чёрных деревьях. Легко видеть, что красно-чёрные деревья изометричны 2-3-4 B-деревьям.
 +
Каждый чёрный узел можно объединить с его красными потомками. Результирующий узел будет иметь не более трех ключей и не более четырех потомков.
 +
 
 +
==Ссылки==
  
 
* [http://rain.ifmo.ru/cat/view.php/vis/trees/red-black-2002 Визуализатор]
 
* [http://rain.ifmo.ru/cat/view.php/vis/trees/red-black-2002 Визуализатор]

Версия 20:04, 22 марта 2012

Пример красно-чёрного дерева.
Красно - чёрное дерево - самобалансирующееся двоичное дерево поиска, в котором баланс осуществляется на основе "цвета" узла дерева, который принимает только два значения: "красный" и "чёрный".

При этом все листья дерева являются фиктивными и не содержат данных.

Свойства

  1. Узел либо красный, либо чёрный.
  2. Все листья — черные.
  3. Оба потомка каждого красного узла — черные.
  4. Всякий простой путь от данного узла до любого листового узла, являющегося его потомком, содержит одинаковое число черных узлов.

Высота красно-черного дерева

Назовем черной высотой дерева с корневой вершиной [math]r[/math] максимальное количество черных вершин во всех ветвях, начинающихся в [math]r[/math] и заканчивающихся в листьях, не считая саму вершину [math]r[/math]. Будем обозначать ее [math]hb(r)[/math].

Лемма. В красно-черном дереве с черной высотой [math]hb[/math] количество внутренних вершин не менее [math]2^{hb+1}-1[/math].

Доказательство. Если рассмотреть лист (фиктивную вершину), то для нее лемма верна. Рассмотрим внутреннюю вершину [math]x[/math]. Пусть [math]hb(x)=h[/math]. Тогда если ее потомок [math]p[/math] - черный, то высота [math]hb(p)=h-1[/math], а если – красный, то [math]hb(p)=h[/math]. Таким образом, по предположению индукции, в поддеревьях содержится не менее [math]2^h-1[/math] вершин, а во всём дереве, соответственно, не менее [math]2^h-1 + 2^h-1 + 1=2^{h+1}-1[/math]. Если обычная высота дерева равна [math]h[/math], то черная высота дерева будет не меньше [math]h/2-1[/math] и, по лемме, количество внутренних вершин в дереве

[math]N \ge 2^{h/2}-1[/math]

Прологарифмировав неравенство, имеем:

[math]\log(N+1) \ge h/2[/math]

[math]2\log(N+1) \ge h[/math]

[math]h \le 2\log(N+1)[/math]

Итак, учитывая, что для любого бинарного дерева [math]h \gt \log(N)[/math], получаем, что доказана следующая

Теорема. Для красно-черного дерева, имеющего [math]N[/math] внутренних вершин, верна следующая оценка для его высоты [math]h=O(\log(N))[/math], или, более точно, [math]\log(N) \lt h \le 2\log(N+1)[/math].

Операции

Вставка элемента

Каждый элемент вставляется вместо листа, поэтому для выбора места вставки идём от корня до тех пор, пока указатель на следующего сына не станет nil(т.е. этот сын - лист). Вставляем вместо него новый элемент с nil-потомками и красным цветом. Теперь проверяем балансировку. Если отец нового элемента красный, то достаточно рассмотреть только два случая:

1. "Дядя" этого узла тоже красный. Тогда просто перекрашиваем "отца" и "дядю" в чёрный цвет, а "деда" - в красный. Проверяем, не нарушает ли он теперь балансировку. Если в результате этих перекрашиваний мы дойдём до корня, то в нём в любом случае ставим чёрный цвет.

D 1.png

2. "Дядя" чёрный. Если выполнить только перекрашивание, то может нарушиться постоянство чёрной высоты дерева по всем ветвям. Поэтому выполняем поворот. Если добавляемый узел был правым потомком, то необходимо сначала выполнить левое вращение, которое сделает его левым потомком.

D 2.png

Удаление вершины

При удалении вершины могут возникнуть три случая в зависимости от количества её детей:

  1. Если у вершины нет детей, то изменяем указатель на неё у родителя на nil.
  2. Если у неё только один ребёнок, то делаем у родителя ссылку на него вместо этой вершины.
  3. Если же имеются оба ребёнка, то находим вершину со следующим значением ключа. У такой вершины нет левого ребёнка. Удаляем уже эту вершину описанным во втором пункте способом, скопировав её ключ в изначальную вершину.

Проверим балансировку дерева. Т.к. при удалении красной вершины свойства дерева не нарушаются, то восстановление балансировки потребуется только при удалении чёрной. Рассмотрим ребёнка удалённой вершины.

1. Если брат этого ребёнка красный, то делаем вращение вокруг ребра между отцом и братом, тогда брат становится родителем отца. Красим его в чёрный, а отца - в красный цвет.

D 3.png

2. Если брат текущей вершины был чёрным, то получаем три случая:

  • Оба ребёнка у брата чёрные. Красим брата в красный цвет и рассматриваем далее отца вершины.

D 4.png

  • Если у брата правый ребёнок чёрный,а левый красный, то перекрашиваем брата и его левого сына и делаем вращение.

D 5.png

  • В же у брата правый ребёнок красный, то перекрашиваем брата в цвет отца, его ребёнка и отца - в чёрный, делаем вращение и выходим из алгоритма.

D 6.png

Продолжаем тот же алгоритм, пока текущая вершина чёрная и мы не дошли до корня дерева. Из рассмотренных случаев ясно, что при удалении выполняется не более трёх вращений.

Объединение красно-чёрных деревьев

Объединение двух красно-чёрных деревьев [math]T_{1}[/math] и [math]T_{2}[/math] по элементу x выполняется, когда [math]key[T_{1}] \leqslant x[/math] и [math]x \leqslant key[T_{2}][/math]. Найдём чёрные высоты деревьев. Предположим также, что [math]hb[T_{1}] \geqslant hb[T_{2}][/math]. Тогда в дереве [math]T_{1}[/math] ищем среди чёрных вершин, имеющих чёрную высоту [math]hb[T_{2}][/math], вершину y с наибольшим ключом. Пусть [math]T_{y}[/math] — поддерево с корнем y. Объединяем это дерево с [math]T_{2}[/math] в одно с красным корнем x. Теперь родителем вершины x становится бывший отец вершины y. Осталось восстановить свойства красно-черного дерева, чтобы у красной вершины не было красных детей. Делается аналогично алгоритму добавления вершины.

Т.к. общее время выполнения каждой из операций порядка высоты дерева ,то все они выполняются за [math]O(\log{n})[/math].

Преимущество красно-чёрных деревьев

Одно из основных преимуществ красно-чёрных деревьев заключается в том, что процедуру балансировки практически всегда можно выполнять параллельно с процедурами поиска, т.к. алгоритм поиска не зависит от аттрибута цвета узлов. Вращение поддеревьев не может выполнятся одновременно с поиском, но при вставке выполняется не более [math]O(1)[/math] вращений.

Красно-чёрные деревья являются наиболее активно используемыми на практике самобалансирующимися деревьями поиска. В частности, ассоциативные контейнеры библиотеки STL (map, set, multiset, multimap) основаны на красно-чёрных деревьях. Легко видеть, что красно-чёрные деревья изометричны 2-3-4 B-деревьям. Каждый чёрный узел можно объединить с его красными потомками. Результирующий узел будет иметь не более трех ключей и не более четырех потомков.

Ссылки