Участник:Flanir1 — различия между версиями
Flanir1 (обсуждение | вклад) (→Операции) |
Flanir1 (обсуждение | вклад) (→Вставка элемента) |
||
Строка 48: | Строка 48: | ||
[[Файл:23treesearch.png|border]] | [[Файл:23treesearch.png|border]] | ||
− | === Вставка элемента === | + | === Вставка элемента === |
+ | *<tex>x</tex> - искомое значение. | ||
+ | *<tex>t</tex> - текущая вершина в дереве. Изначально <tex>t = \mathtt{root}</tex> | ||
+ | Если корня не существует {{---}} дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом: | ||
+ | |||
+ | Найдем сперва, где бы находился элемент, применив search(x). Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент - лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания. | ||
+ | |||
+ | Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало 4, то разделим родителя на два узла, и повторим разделение теперь для его родителя. | ||
+ | |||
+ | splitParent('''Node''' t): | ||
+ | '''if''' (t.length > 3) | ||
+ | Node a; | ||
+ | a.sons[0] = t.sons[2] | ||
+ | a.sons[1] = t.sons[3] | ||
+ | t.sons[2].parent = a | ||
+ | t.sons[3].parent = a | ||
+ | a.keys[0] = t.keys[2] | ||
+ | a.length = 2 | ||
+ | t.length = 2 | ||
+ | t.sons[2] = '''null''' | ||
+ | t.sons[3] = '''null''' | ||
+ | '''if''' (t.parent != '''null''') | ||
+ | t.parent[t.length] = a | ||
+ | t.length++ | ||
+ | сортируем сыновей у t.parent | ||
+ | splitParent(t.parent) | ||
+ | '''else''' //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем | ||
+ | Node t = root | ||
+ | root.sons[0] = t | ||
+ | root.sons[1] = a | ||
+ | t.parent = root | ||
+ | a.parent = root | ||
+ | root.length = 2 | ||
+ | сортируем сыновей у root | ||
+ | Если сыновей стало 3, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня: | ||
+ | updateKeys('''Node''' t): | ||
+ | Node a = t.parent | ||
+ | '''while''' (a != '''null''') | ||
+ | '''for''' i = 0 .. a.length - 1 | ||
+ | a.keys[i] = max(a.sons[i]) //max - возвращает максимальное значение в поддереве. | ||
+ | a = a.parent //Примечание: max легко находить, если хранить максимум | ||
+ | //правого поддерева в каждом узле {{---}} это значение и будет max(a.sons[i]) | ||
+ | |||
+ | <tex>\mathtt{updateKeys}</tex> необходимо запускать от нового узла. | ||
+ | |||
+ | Код для добавления: | ||
+ | insert('''int''' x): | ||
+ | Node n = Node(x) | ||
+ | '''if''' (root == null) | ||
+ | root = n | ||
+ | return | ||
+ | Node a = search(x) | ||
+ | '''if''' (a.parent == '''null''') | ||
+ | Node t = root | ||
+ | root.sons[0] = t | ||
+ | root.sons[1] = n | ||
+ | t.parent = root | ||
+ | n.parent = root | ||
+ | root.length = 2 | ||
+ | сортируем сыновей у root | ||
+ | '''else''' | ||
+ | Node p = a.parent | ||
+ | p.sons[p.length] = n | ||
+ | p.length++ | ||
+ | n.parent = p | ||
+ | сортируем сыновей у p | ||
+ | split(n) | ||
+ | updateKeys(n) | ||
=== Удаление элемента === | === Удаление элемента === |
Версия 15:52, 10 мая 2015
2-3 дерево — структура данных, представляющая собой сбалансированное дерево поиска, такое что из каждого узла может выходить две или три ветви и глубина всех листьев одинакова. 2-3 дерево можно обобщить до B+-дерева.
Содержание
Свойства
2-3 дерево — сбалансированное дерево поиска, обладающее следующими свойствами:
- нелистовые вершины имеют либо 2, либо 3 сына,
- нелистовая вершина, имеющая двух сыновей, хранит максимум левого поддерева. Нелистовая вершина, имеющая трех сыновей, хранит два значения.Первое значение хранит максимум левого поддерева, второе максимум центрального поддерева,
- сыновья упорядочены по значению максимума поддерева сына,
- все листья лежат на одной глубине,
- Высота 2-3 дерева , где - количество элементов в дереве.
Теорема: |
Высота 2-3 дерева , где - количество элементов в дереве. |
Доказательство: |
Из построения следует, что все листья лежат на одной глубине, так как элементов | , то получаем что высота равна
Операции
Введем следующие обозначения:
- - корень 2-3 дерева
Каждый узел дерева обладает полями:
- - сыновья узла,
- - ключи узла,
- - количество сыновей.
Поиск
- - искомое значение.
- - текущая вершина в дереве. Изначально
Будем просматривать ключи в узлах, пока узел не является листом.Рассмотрим два случая: 1)у текущей вершины два сына. Если её значение меньше
, то , иначе .2)у текущей вершины три сына. Если второе значение меньше
, то . Если первое значение меньше , то , иначе .Node search(int x): Node t = root while (t не является листом) if (t.length == 2) if (t.keys[0] < x) t = t.sons[1] else t = t.sons[0] else if (t.keys[1] < x) t = t.sons[2] else if (t.keys[0] < x) t = t.sons[1] else t = t.sons[0] return t
Пример поиска в 2-3 дереве, так как элемент 6 существует, то был возвращен корректный узел, так как элемента 10 нет, возвращается некорректный узел. На основе этого можно сделать метод
, проверяющий наличии элемента в деревеВставка элемента
- - искомое значение.
- - текущая вершина в дереве. Изначально
Если корня не существует — дерево пустое, то новый элемент и будет корнем (одновременно и листом). Иначе поступим следующим образом:
Найдем сперва, где бы находился элемент, применив search(x). Далее проверим есть ли у этого узла родитель, если его нет, то в дереве всего один элемент - лист. Возьмем этот лист и новый узел, и создадим для них родителя, лист и новый узел расположим в порядке возрастания.
Если родитель существует, то подвесим к нему ещё одного сына. Если сыновей стало 4, то разделим родителя на два узла, и повторим разделение теперь для его родителя.
splitParent(Node t): if (t.length > 3) Node a; a.sons[0] = t.sons[2] a.sons[1] = t.sons[3] t.sons[2].parent = a t.sons[3].parent = a a.keys[0] = t.keys[2] a.length = 2 t.length = 2 t.sons[2] = null t.sons[3] = null if (t.parent != null) t.parent[t.length] = a t.length++ сортируем сыновей у t.parent splitParent(t.parent) else //мы расщепили корень, надо подвесить его к общему родителю, который будет новым корнем Node t = root root.sons[0] = t root.sons[1] = a t.parent = root a.parent = root root.length = 2 сортируем сыновей у root
Если сыновей стало 3, то ничего не делаем. Далее необходимо восстановить ключи на пути от новой вершины до корня:
updateKeys(Node t): Node a = t.parent while (a != null) for i = 0 .. a.length - 1 a.keys[i] = max(a.sons[i]) //max - возвращает максимальное значение в поддереве. a = a.parent //Примечание: max легко находить, если хранить максимум //правого поддерева в каждом узле — это значение и будет max(a.sons[i])
необходимо запускать от нового узла.
Код для добавления:
insert(int x): Node n = Node(x) if (root == null) root = n return Node a = search(x) if (a.parent == null) Node t = root root.sons[0] = t root.sons[1] = n t.parent = root n.parent = root root.length = 2 сортируем сыновей у root else Node p = a.parent p.sons[p.length] = n p.length++ n.parent = p сортируем сыновей у p split(n) updateKeys(n)
Удаление элемента
Слияние двух деревьев
Cсылки
- is.ifmo.ru - Визуализатор 2-3 дерева — 1
- rain.ifmo.ru - Визуализатор 2-3 дерева — 2
- Википедия — 2-3 дерево
- Д. Кнут «Искусство программирования. Сортировка и поиск», часть 6.2.4