Лекция 5 Элементарные структуры данных часть 3
TRANSCRIPT
Двоичные деревья поиска
Двоичным называется дерево с максимальной степенью вершины равной двум
В двоичном дереве каждая вершина может иметь(или не иметь) правого и левого ребенка.
Двоичные деревья поиска
Двоичным деревом поиска называется такое двоичное дерево в котором элементы хранятся в соответствии с принципом упорядоченности:
Пусть вершина x-произвольная вершина двоич- ного дерева поиска. Если вершина y находится в левом поддереве вершины x, то выполняется неравенство , если у – в правом поддереве вершины x, то выполняется неравенство
keyxkeyy
keyxkeyy
Двоичные деревья поиска
Свойство упорядоченности позволяет простореализовать вывод отсортированного множества элементов двоичного дерева поиска.
void InOrderTreeWalk(x){if(x!=null){
InOrderTreeWalk(x->left);Print(x);InOrderTreeWalk(x->right);
}}
5
3
2 5
7
8
Двоичные деревья поиска
Поиск элемента в двоичном дереве поиска занимает время O(h), где h-высота дерева.void TreeSearch(x,key){ if ((x==null)||(key=x->key)) return x; if (key<x->key) return TreeSearch(x->left, key); else return TreeSearch(x->right, key);}void IterativeTreeSearch(x,key){ while((x==null)&&(key=x->key)){ if (key<x->key) x = x->left; else x = x->right; } return x;}
Двоичные деревья поиска
void TreeMinimum(x){ while(x->left!=null)
x=x->left; return x;}
void TreeMaximum(x){ while(x->right!=null)
x=x->right; return x;}
5
3
2 5
7
8
В двоичном дереве поиска самый левый лист – минимум, самый правый лист - максимум.
Двоичные деревья поиска
void TreeNext(x){ if(x->right!=null) return TreeMinimum(x->right); y = x->parent; while((y!=null)&&(x==y->right)){ x = y; y = x->parent; } return y; }
5
3
2 5
7
8
void TreePrevious(x){ if(x->left!=null) return TreeMaximum(x->left); y = x->parent; while((y!=null)&&(x==y->left)){ x = y; y = x->parent; } return y; }
Двоичные деревья поиска
Если вершина имеет двоичного дерева поиска имеет двух детей, то следующая за ней вершина не имеет левого ребенка, а предшествующая ей вершина – правого.
Это обстоятельство используется в алгоритме удаления вершины, для того чтобы сохранить свойство упорядоченности для двоичного дерева поиска.
Двоичные деревья поиска5
3
2 5
7
8
void TreeInsert(root,z){ y = null; x = root; while (x!=null){ y=x; if (z->key < x->key) x = x->left; else x = x->right; } z->parent = y; if (y==null) root=z; else { if (z->key < y->key) y->left = z; else y->right = z; }}
4
5
3
2 5
7
8
Двоичные деревья поиска
void TreeDelete(root,z){ if ((z->left==null)||(z->right==null))
y = z; else y = TreeNext(z); if (y->left !=null) x = y->left; else x = y->right; if (x!=null) x->parent = y->parent; if (y->parent == null) root=x; else { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } if (y!=z) { Copy(z,y); }}
4
5
3
2 5
7
8
5
4
2 5
7
8
Двоичные деревья поиска
Операции поиска, нахождения минимального и максимального, следующего и предыдущего элементов, а также добавления и удаления в двоичном дереве поиска работают со скоростью O(h), где h – высота дерева.
Высота случайно построенного двоичного дерева пропорциональна log n (n-общее количество элементов). Однако это не гарантировано и в худшем случае высота дерева пропорциональна n.
Красно-черные деревья
Для того чтобы высота дерева была пропорциональна log n, должны соблюдаться требования, гарантирующие что глубины любых двух листьев различаются не более чем в два раза.
Деревья, обладающие такими свойствами, называют сбалансированными.
Разновидностью сбалансированных деревьев являются красно-черные деревья.
Красно-черные деревья
Двоичное дерево поиска называется красно-черным,если оно обладает следующими свойствами (RB-свойствами): Каждая вершина – либо красная, либо черная. Каждый лист (nil, null) – черный. Если вершина красная – оба ее ребенка черные. Все пути от корня к листьям содержат одинаковое
количество черных вершин.
Красно-черные деревья
19
26
17
14 21
41
4730
20
null null
null
23
null null
28
null null
null null38
35 39
null nullnull null10
16
15
7 12
3
null null
null nullnull null
null
null
Красно-черные деревья
Теорема. Красно-черное дерево с n внутреннимивершинами,(т.е. не считая null-листьев) имеетвысоту не больше 2log(n+1).
Таким образом красно-черное дерево являетсясбалансированным.
Красно-черные деревья
Работать с красно-черными деревьями можно так же как и с обычными двоичными деревьями поиска. Однако при добавлении или удалении вершины дерево может потерять RB-свойства, т.е. разбалансироваться.
Чтобы восстановить RB-свойства, надо перекрасить некоторые вершины и изменить структуру дерева.
Структура дерева меняется с помощью вращений.
Красно-черные деревьяx
yα
β γ
x
y
α β
γ
void LeftRotate(root,x){ y = x->right; x->right = y->left; if ( y->left != null) y->left->parent = x; y->parent = x->parent; if (x->parent == null) root = y; else{ if (x == x->parent->left) x->parent->left = y; else x->parent->right= y; } y->left = x; x->parent = y;}
Левое вращение
Красно-черные деревья
11
14
x
15
2
1 7
5
4
8y
В алгоритме добавления вершины к красно-черному дереву вновь добавляемую вершину окрашивают в красный цвет, а корень всегда оставляют черным.
После добавления вершины x (4), не выполняется RB-свойство №3. Вершина 5 не может иметь красного ребенка.
Красно-черные деревья
Пусть y – «дядя» x. Если обе вершины красные, то перекрашиваем y и родителя x в черный цвет, а «деда» x в красный.
Теперь RB-свойство №3 не выполняется для вершины 7.Однако «дядя» у 7 – черный.
11
14
x 15
2
1 7
5 8
y
4
Красно-черные деревья
Произведем левое вращение относительно x. Результат снова не обладает всеми RB-свойствами для вершины 2.
Разница по сравнению с предыдущем случаем состоит в том, что 2 – левый ребенок своего родителя, а 7 – была правым.
11
14
x152
1
7
5
8
y
4
Красно-черные деревья
Перекрашиваем «деда» x в красный цвет, родителя в черный. Произведем правое вращение относительно «деда» x.
Результат обладает всеми RB-свойствами.
11
14
15
2
1
7
5 8
4
Красно-черные деревья
В рассмотренном примере вершина x (нарушающая RB-свойства дерева) всегда была левой по отношению к своему «деду».
Если она окажется справа от «деда», то возникают еще три случая, решающие задачу балансировки дерева симметрично предыдущим трем.
Красно-черные деревья
При удалении вершины из красно-черного дерева действуют по тому же алгоритму что и в обычных двоичных деревьях поиска.
Если удаляемая вершина – красная, RB-свойства после удаления нарушены не будут.
Если удаляемая вершина – черная. Путь проходивший через нее будет содержать на одну черную вершину меньше (св-во №4).
Красно-черные деревья
D
E
A
B
C
D
E
A
B
Cα β
γ δ ε ζ γ δ
ε ζ
α β
x
x
w
w
Случай №1. Производим вращение и перекрашиваем вершины как показано на рисунке. Случай №1 сводится таким образом к случаям 2,3 или 4. (x- элемент вставший на место удаленной вершины).
Красно-черные деревья
D
E
A
B
Cα β
γ δ ε ζ
x w
c
D
E
A
B
Cα β
γ δ ε ζ
x c
Случай №2. Перекрашиваем вершины как показано на рисунке. Продолжаем просматривать дерево для родителя x.
Красно-черные деревья
D
E
A
B
Cα β
γ δ ε ζ
x w
c
D
E
A
B
C
α β γ
δ
ε ζ
x
c
w
Случай №3. Производим вращение и перекрашиваем вершины как показано на рисунке. Случай №3 сводится таким образом к случаю 4.
Красно-черные деревья
D
E
A
B
C
D
E
A
B
Cα β
γ δ ε ζ γ δ
ε ζ
α β
x
x
w
w
c c
Случай №4. Производим вращение и перекрашиваем вершины как показано на рисунке. Случай №4 исправляет недостаток черных вершин и просмотр дерева можно завершить. Просмотр также завершается если новая х будет красной.
Красно-черные деревья
Все словарные операции, включая добавление и удаление вершин, работают для красно-черных деревьев со скоростью log(n).
Красно-черные деревья – динамическая структура данных, сочетающая в себе динамические свойства связанных списков и более быстрые словарные операции, характерные для хеш-таблиц.