+ All Categories
Home > Documents > Алгоритмы на деревьях.

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

Date post: 01-Jan-2016
Category:
Upload: jelani-dixon
View: 43 times
Download: 1 times
Share this document with a friend
Description:
Алгоритмы на деревьях. Определение дерева. 8. class Tree { static private class TreeNode { Object key; TreeNode left, right; public TreeNode(Object key, TreeNode left, TreeNode right) { this .key = key; - PowerPoint PPT Presentation
28
Алгоритмы на деревьях. 8 10 9 6 3 1 4 12 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); } } Определение дерева
Transcript

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

8

10

9

6

3

1 4

12

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); }

}

Определение дерева

Простые рекурсивные алгоритмы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); }

Внутренний итератор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); } }); }}

Внешний итератор

8

10

9

6

3

1 4

12

8

6

3

1 3 4 6 8

10

9 10 12

Внешний итератор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); }}

Внешний итератор для обхода дерева «по уровням»

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); }}

Деревья поиска. Индексация и поиск данных.

interface Comparable { int compareTo(Object obj);}

8

10

9

6

3

1 4

12

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

6

3

1 4

12

на; 12

берегу; 6

пустынных; 1

волн; 4

стоял; 9

он; 10

дум; 3

великих; 8

Индексация данных

С помощью поиска по индексу можно получить ответы на вопросы:

Какое слово встречается ровно 6 раз? Какие слова встречаются больше 10 раз?

Какое слово встречается чаще всего?

Добавление данных в лист дерева

8

10

9

6

3

1 4

12

11

7

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; }}

Добавление данных в корень дерева

6

3

1 4

8

10

9 12

7public 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); }}

Сбалансированные по высоте (АВЛ) деревья

8

10

9

6

3

1 4

12

0 0

0 0 0

0

1

21

01

В общем случае трудно придумать алгоритм, позволяющий сбалансировать произвольное дерево, но можно предложить алгоритм балансировки дерева после добавления или удаления одного узла.

7

94

1 6

3

0 0

0

0

1

0

10

13

12 15

1

0

00

-1

1

20

0

Алгоритм «простого поворота»

3

2

11

1

2

IV

III

III

(I) < (1) < (II) < (2) < (III) < (3) < (IV)

1. Отсоединение поддеревьев

(h) (h-1)

(h)

(h)

2. Поворот0

0

3. Присоединение поддеревьев

Алгоритм «двойного поворота»

3

1

21

-1

2

IV

I

IIIII

(I) < (1) < (II) < (2) < (III) < (3) < (IV)

1. Отсоединение поддеревьев

(h) (h-1)

(h)

(h)

2. Поворот3. Присоединение поддеревьев

0

0

-1

Пример вставки ключа

10

6 15

3 8 12 20

1 18 23

1

1 0

0

0

0

00

170

1

01

-1-2

-1

-1

10

6

153 8

121

1

1 0

0

0

17

18

20

230 0

0

0

0

-1

Красно-черные деревья

17

14 21

19 2310

7 12

Свойства красно-черных деревьев

Корень и пустые узлы всегда имеют черный цвет Красная вершина не может иметь красных потомков

Максимальные «черные» длины путей, ведущих из корня к листьям (пустым узлам), одинаковы

Красно-черные деревья поиска достаточно эффективны:число шагов при поиске не превышает 2 log2 n

Существуют эффективные процедуры добавления и удаления узлов, которые не нарушают свойств красно-черных деревьев

16

15 20

3

Алгоритм добавления ключа в красно-черное дерево

17

10 26

21 296

4 7

15

13 24

1

1. Добавляем ключ 19

19

2. Добавляем ключ 20

20

3. Добавляем ключ 11

11

4. Добавляем ключ 3…

3

Хранение дополнительной информации в деревьях.

Задача: по заданному порядковому номеру найти узел дерева;и наоборот, по заданному узлу найти его порядковый номер.

1712

147

214

192

231

104

72

121

162

151

201

31

Решение: в каждом узле хранить размер поддерева с корнем в этом узле

3

7

10

12

14

15

16

17

19

20

21

23

Массив:

0

1

2

3

4

5

6

7

8

9

10

11

Алгоритмы работы с индексами в двоичных деревьях с размерами

Поиск позиции по индексу:

TreeNode findByIndex(int i)

1. Начинаем цикл поиска с корняcurrent = root;

2. Если в левом поддереве (== i) узлов,return current;

3. Если в левом поддереве (> i) узлов,current = current.left;

4. Если в левом поддереве (< i) узлов,i -= (current.left.size + 1);current = current.right;

1712

147

214

192

231

104

72

121

162

151

201

31

Вход: i == 5

Выход: key == 15

i = 5

i = 0

Программа поиска позиции узла в дереве по индексу

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; } } }

Алгоритмы работы с индексами в двоичных деревьях с размерами

Поиск индекса по позиции:

TreeNode findByPosition(TreeNode node)

1. Начинаем цикл поиска с узла node;ndx = node.left.size;

2. Если узел справа от родительского,ndx += (brother.size+1);

3. Переходим к родительскому узлу,node = node.parent;

1712

147

214

192

231

104

72

121

162

151

201

31

Вход: key == 16

Выход: ndx == 6

ndx = 1ndx = 6

Программа поиска индекса узла в дереве по позиции

class Tree { private TreeNode root = null;

public static class TreeNode { Comparable info; int size; TreeNode parent, left, right; }

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; }

Преобразование информации о размерах при вращениях

BsB

AsA

s1 s2

s3

sA == s1 + s2 + 1

sB == sA + s3 + 1

Алгоритм: int prev_sA = sA;sA = sB;sB += s2 – prev_sA;

BsB

s3s2

AsA

s1

sA == s1 + sB + 1

sB == s2 + s3 + 1

2-3-дерево

18 32

7 13 37 4124

21 26 29 34 39 44 46169 121 4

Структура 2-3-дерева:

Каждый узел содержит 1 или 2 ключа Ключи упорядочены (возможен быстрый поиск) Промежуточные узлы имеют все ссылки (2 или 3 ссылки) Все терминальные узлы (листья) находятся на одном уровне

Алгоритмы вставки ключа в 2-3-дерево

18 32

7 13 37 4124

21 26 29 34 39 46169 121 4

Новый ключ вставляется в лист одним из трех методов:

Расширением терминального узла «Переливанием» Расщеплением узлов

3348

44

0

Алгоритмы удаления ключа из 2-3-дерева

18 32

7 13 37 4124

21 26 29 34 39 46169 121 4

Существующий ключ переносится в лист и удаляется одним из трех методов:

Сужением терминального узла «Переливанием» Склеиванием узлов

44

Обобщение 2-3-дерева – В-дерево k-го порядка

Структура В-дерева:

Корневой узел содержит от 1 до 2*k ключей

Ключи упорядочены (возможен быстрый поиск) Промежуточные узлы имеют все ссылки (корень – от 2, остальные – от (k+1) до (2*k+1) ссылки)

Все терминальные узлы (листья) находятся на одном уровне

Прочие узлы содержат от k до 2*k ключей

Пример структуры при k = 3

Расщепление узла В-дерева k-го порядка при вставке ключа

(2 * k + 1) ключ

1. При вставке ключа в терминальный узел образовалось переполнение узла

k кл. k кл.1

2. Делим узел на 3 узла: k, 1 и k ключей

3. Перемещаем средний ключ на предыдущий уровень

Модифицированное В-дерево (В+-дерево)

1. Только терминальные узлы содержат ссылки на данные; промежуточные узлы служат только для поиска информации.

2. При расщеплении узла происходит создание копии ключа:

2*k + 1k + 1 k

1

3. При слиянии узлов ключ, пришедший с более высокого уровня, уничтожается:

1

k-1 k2*k - 1


Recommended