1 / 28

Алгоритмы на деревьях.

Алгоритмы на деревьях. Определение дерева. 8. class Tree { static private class TreeNode { Object key; TreeNode left, right; public TreeNode(Object key, TreeNode left, TreeNode right) { this .key = key;

Download Presentation

Алгоритмы на деревьях.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Алгоритмы на деревьях. Определение дерева 8 class Tree { static private class TreeNode { Object key; TreeNode left, right; public TreeNode(Object key, TreeNode left, TreeNode right) { this.key = key; this.left = left; this.right = right; } public TreeNode(Object key) { this(key, null, null); } } TreeNode root = null; public Tree() {} public Tree(Tree left, Object key, Tree right) { root = new TreeNode(key, left.root, right.root); } } 10 6 3 9 12 1 4

  2. Простые рекурсивные алгоритмы class Tree { static private class TreeNode { Object key; TreeNode left, right; } TreeNode root = null; public int height() { return height(root); } private int height(TreeNode root) { if (root == null) return 0; else return Math.max(height(root.left), height(root.right)) + 1; } public int level(int n) { return level(root, n); } private int level(TreeNode root, int n) { return root == null ? 0 : n == 0 ? 1 : level(root.left, n-1) + level(root.right, n-1); } }

  3. Внутренний итератор public interface Visitor { void visit(Object node); } class Tree { static private class TreeNode { Object key; TreeNode left, right; } TreeNode root = null; public void iterate(Visitor v) { iterate(root, v); } private void iterate(TreeNode root, Visitor v) { if (root != null) { iterate(root.left, v); v.visit(root.key); iterate(root.right, v); } } } class Main { public static void main(String[] args) { Tree t = ...; t.iterate(new Visitor() { public void visit(Object node) { System.out.println(node); } }); } }

  4. Внешний итератор 10 8 8 6 3 10 6 3 9 12 1 4 1 4 6 8 9 10 12 3

  5. Внешний итератор class Tree { private static class TreeIterator implements Iterator { Stack stk = new Stack(); TreeNode current; public TreeIterator(TreeNode root) { current = root; if (current != null) findLeft(); } private void findLeft() { while (current.left != null) { stk.push(current); current = current.left; } } public boolean hasNext() { return current != null; } public Object next() { if (current == null) throw new NoSuchElementException(); TreeNode res = current; current = current.right; if (current != null) findLeft(); else if (!stk.isEmpty()) { current = (TreeNode)stk.pop(); } return res.key; } public void remove() { throw new UnsupportedOperationException(); } } public Iterator iterator() { return new TreeIterator(root); } }

  6. Внешний итератор для обхода дерева «по уровням» class Tree { private static class TreeIterator1 implements Iterator { Queue que = new Queue(); public TreeIterator1(TreeNode root) { if (root != null) que.enqueue(root); } public boolean hasNext() { return !que.isEmpty(); } public Object next() { if (que.isEmpty()) throw new NoSuchElementException(); TreeNode res = (TreeNode)que.dequeue(); if (res.left != null) que.enqueue(res.left); if (res.right != null) que.enqueue(res.right); return res.ref; } public void remove() { throw new UnsupportedOperationException(); } } public Iterator iterator() { return new TreeIterator(root); } }

  7. 6 3 12 1 4 Деревья поиска. Индексация и поиск данных. Поиск в дереве по ключу interface Comparable { int compareTo(Object obj); } class Tree { static private class TreeNode { Comparable key; Object ref; TreeNode left, right; } TreeNode root = null; public Object search(Comparable key) { for (TreeNode current = root; current != null; ) { int res = key.compareTo(current.key); if (res < 0) { current = current.left; } else if (res == 0) { return current.ref; } else { // res > 0 current = current.right; } } return null; } } Ищем ключ 9 8 10 9

  8. на; 12 берегу; 6 пустынных; 1 волн; 4 8 стоял; 9 он; 10 10 6 дум; 3 великих; 8 3 9 12 1 4 Индексация данных С помощью поиска по индексу можно получить ответы на вопросы: • Какое слово встречается ровно 6 раз? • Какие слова встречаются больше 10 раз? • Какое слово встречается чаще всего?

  9. 8 7 10 6 11 3 9 12 1 4 Добавление данных в лист дерева public void addLeaf(Comparable key, Object obj) { TreeNode newNode = new TreeNode(key, obj); TreeNode current = root; TreeNode pred = null; while (current != null) { int res = key.compareTo(current.key); if (res == 0) return; else { pred = current; current = (res < 0 ? current.left : current.right); } } if (pred == null) root = newNode; else { if (key.compareTo(pred.key) < 0) pred.left = newNode; else pred.right = newNode; } }

  10. 8 10 6 3 9 12 1 4 Добавление данных в корень дерева public void addRoot(Comparable key, Object obj) { TreeNode newNode = new TreeNode(key, obj); addRoot(key, root, newNode, 0, newNode, 1); root = newNode; } private void addRoot(Comparable key, TreeNode current, TreeNode leftRef, int lrLeft, TreeNode rightRef, int lrRight) { if (current == null) { if (lrLeft == 0) leftRef.left = null; else leftRef.right = null; if (lrRight == 0) rightRef.left = null; else rightRef.right = null; } else if (key.compareTo(current.key) > 0) { if (lrLeft == 0) leftRef.left = current; else leftRef.right = current; addRoot(key, current.right, current, 1, rightRef, lrRight); } else { if (lrRight == 0) rightRef.left = current; else rightRef.right = current; addRoot(key, current.left, leftRef, lrLeft, current, 0); } } 7

  11. 1 10 0 13 0 0 12 15 Сбалансированные по высоте (АВЛ) деревья 1 8 2 0 1 2 1 0 7 10 6 0 1 0 0 1 0 0 0 0 4 9 3 9 12 -1 0 0 0 0 1 6 1 4 0 3 В общем случае трудно придумать алгоритм, позволяющий сбалансировать произвольное дерево, но можно предложить алгоритм балансировки дерева после добавления или удаления одного узла.

  12. Алгоритм «простого поворота» 1. Отсоединение поддеревьев 2. Поворот 2 0 3. Присоединение поддеревьев 3 0 1 IV 2 (h) 1 III 1 (h) I II (h) (h-1) (I) < (1) < (II) < (2) < (III) < (3) < (IV)

  13. Алгоритм «двойного поворота» 1. Отсоединение поддеревьев 2. Поворот 2 0 3. Присоединение поддеревьев 3 0 -1 -1 1 IV (h) I 1 (h) 2 II III (h) (h-1) (I) < (1) < (II) < (2) < (III) < (3) < (IV)

  14. 0 10 1 0 6 18 1 0 -1 0 3 8 15 20 0 0 0 0 12 17 23 1 Пример вставки ключа 0 10 1 -2 -1 6 15 0 1 0 -1 1 0 3 8 12 20 0 1 0 -1 0 1 18 23 0 17

  15. Красно-черные деревья 17 Свойства красно-черных деревьев • Корень и пустые узлы всегда имеют черный цвет 14 21 • Красная вершина не может иметь красных потомков • Максимальные «черные» длины путей, ведущих из корня к листьям (пустым узлам), одинаковы 10 16 19 23 7 12 15 20 3 Красно-черные деревья поиска достаточно эффективны:число шагов при поиске не превышает 2 log2 n Существуют эффективные процедуры добавления и удаления узлов, которые не нарушают свойств красно-черных деревьев

  16. Алгоритм добавления ключа в красно-черное дерево 17 • Добавляем ключ 19 • Добавляем ключ 20 10 26 • Добавляем ключ 11 • Добавляем ключ 3… 6 15 21 29 19 4 7 13 24 1 11 20 3

  17. 1712 147 21 4 Массив: 3 0 7 1 104 16 2 19 2 23 1 10 2 12 3 14 4 15 5 72 12 1 15 1 20 1 16 6 17 7 19 8 31 20 9 21 10 23 11 Хранение дополнительной информации в деревьях. Задача: по заданному порядковому номеру найти узел дерева; и наоборот, по заданному узлу найти его порядковый номер. Решение: в каждом узле хранить размер поддерева с корнем в этом узле

  18. Алгоритмы работы с индексами в двоичных деревьях с размерами Поиск позиции по индексу: 1712 i = 5 TreeNode findByIndex(int i) • Начинаем цикл поиска с корняcurrent = root; 147 21 4 • Если в левом поддереве (== i) узлов,return current; • Если в левом поддереве (> i) узлов,current = current.left; 104 16 2 19 2 23 1 i = 0 • Если в левом поддереве (< i) узлов,i -= (current.left.size + 1);current = current.right; 72 12 1 15 1 20 1 Вход:i == 5 Выход:key == 15 31

  19. Программа поиска позиции узла в дереве по индексу class Tree { private TreeNode root = null; public static class TreeNode { Comparable info; int size; TreeNode parent, left, right; } private TreeNode findByIndex(int i) { // Pre: root != null && // 0 <= i < root.size TreeNode current = root; for (;;) { // Inv: 0 <= i < current.size int sizeL = 0; if (current.left != null) sizeL = current.left.size; if (i == sizeL) return current; else if (i < sizeL) current = current.left; else { i -= sizeL+1; current = current.right; } } }

  20. Алгоритмы работы с индексами в двоичных деревьях с размерами Поиск индекса по позиции: 1712 TreeNode findByPosition(TreeNodenode) • Начинаем цикл поиска с узла node;ndx = node.left.size; 147 21 4 • Если узел справа от родительского,ndx += (brother.size+1); • Переходим к родительскому узлу,node = node.parent; 104 16 2 19 2 23 1 ndx = 1 ndx = 6 Вход:key == 16 Выход:ndx == 6 72 12 1 15 1 20 1 31

  21. Программа поиска индекса узла в дереве по позиции private int findByPosition(TreeNode node) { int ndx = 0; if (node.left != null) ndx += node.left.size; for (TreeNode p = node.parent; p != null; p = p.parent) { if (p.right == node) { int sizeL = 0; if (p.left != null) sizeL = p.left.size; ndx += sizeL+1; } node = p; } return ndx; } class Tree { private TreeNode root = null; public static class TreeNode { Comparable info; int size; TreeNode parent, left, right; }

  22. B sB A sA s1 s3 B sB A sA s1 s2 s2 s3 sA == s1 + sB + 1 sA == s1 + s2 + 1 sB == s2 + s3 + 1 sB == sA + s3 + 1 Алгоритм: int prev_sA = sA; sA = sB; sB += s2 – prev_sA; Преобразование информации о размерах при вращениях

  23. 2-3-дерево 18 32 7 13 24 37 41 1 4 9 12 16 21 26 29 34 39 44 46 Структура 2-3-дерева: • Каждый узел содержит 1 или 2 ключа • Ключи упорядочены (возможен быстрый поиск) • Промежуточные узлы имеют все ссылки (2 или 3 ссылки) • Все терминальные узлы (листья) находятся на одном уровне

  24. Алгоритмы вставки ключа в 2-3-дерево 0 48 18 32 33 7 13 24 37 41 1 4 9 12 16 21 26 29 34 39 44 46 Новый ключ вставляется в лист одним из трех методов: • Расширением терминального узла • «Переливанием» • Расщеплением узлов

  25. Алгоритмы удаления ключа из 2-3-дерева 18 32 7 13 24 37 41 1 4 9 12 16 21 26 29 34 39 44 46 Существующий ключ переносится в лист и удаляется одним из трех методов: • Сужением терминального узла • «Переливанием» • Склеиванием узлов

  26. Обобщение 2-3-дерева – В-дерево k-го порядка Пример структуры при k = 3 Структура В-дерева: • Корневой узел содержит от 1 до 2*k ключей • Прочие узлы содержат от k до 2*k ключей • Ключи упорядочены (возможен быстрый поиск) • Промежуточные узлы имеют все ссылки (корень – от 2, остальные – от (k+1) до (2*k+1) ссылки) • Все терминальные узлы (листья) находятся на одном уровне

  27. Расщепление узла В-дерева k-го порядка при вставке ключа (2 * k + 1)ключ k кл. 1 k кл. • При вставке ключа в терминальный узел образовалось переполнение узла • Делим узел на 3 узла: k, 1 и k ключей • Перемещаем средний ключ на предыдущий уровень

  28. Модифицированное В-дерево (В+-дерево) • Только терминальные узлы содержат ссылки на данные; промежуточные узлы служат только для поиска информации. • При расщеплении узла происходит создание копии ключа: 1 2*k + 1 k + 1 k • При слиянии узлов ключ, пришедший с более высокого уровня, уничтожается: 1 k-1 2*k - 1 k

More Related