Хакасский государственный университет им. Н.Ф. Катанова
Структуры и алгоритмы обработки данных
Лекция: Деревья
Николай Гребенщиков, www.grebenshikov.ru
Дерево - конечное множество T одного или более узлов соследующими свойствами:
1. ∃ один выделенный узел, а именно - корень даннго дереваT .
2. остальные узлы распределены среди m ≥ 0 непересека-ющихся множеств T1, . . . , Tm, и каждое из этих множествявляется деревом (деревья T1, . . . , Tm называются подде-ревьями).
Дерево - ориентированный, ацикличный, связный граф.
1
Дерево используется для представления иерархических свя-зей типа “Один ко многим”.
Что можно представить в виде дерева?
2
Способы изображения
{A, {B, {H} , {J}} , {C, {D} , {E, {G}} , {F}}}
3
Способы изображения
a− b ∗ (c/d + e/f)
4
Нотация
КореньРодительРебёнокПредкиПотомкиБратья
5
Бинарное дерево - конечно множество узлов, которое мо-жет быть либо пустым, либо состоять из корня с двумя дру-гими бинарными поддеревьями
6
Обход дерева - метод исследования дерева, при которомкаждый узел песещается ровно один раз.
• Прямой порядок: корень, все поддеревья начиная с само-го левого
• Обратный порядок
• Центрированный порядок (только для бинарного дерева)
7
АТД Дерево
1 interface Action<T> {2 void doAction(T o);3 }4
5 interface Tree<T> {6 T getData();7 void setData(T o);8 Tree<T> getLeftMostChild();9 Tree<T> getRightMostChild();10 Tree<T> getLeftSibling();11 void setLeftSibling(Tree<T> sibling);12 Tree<T> getRightSibling();13 void setRightSibling(Tree<T> sibling);14 Tree<T> getParent();
8
15 void setParent(Tree<T> parent);16 void insertChildAsRightMost(Tree<T> child);17 void preOrder(Action<T> a);18 void postOrder(Action<T> a);19 void levelPreOrder(Action<T> a);20 void descendantsPreOrder(Action<T> a);21 void parentsFromRoot(Action<T> a);22 }
Прямой обход
1 public void preOrder(Action<T> a) {2 a.doAction(data);3 Tree<T> child = leftMostChild;4 while(null != child) {5 child.preOrder(a);6 child = child.getRightSibling();7 }8 }
9
Класс действия для прохода
1 class PrintData implements Action<Integer> {2 public void doAction(Integer data) {3 try {4 wr.write(data + "␣");5 } catch (Exception e) {}6 }7 }
10
Представление деревьев с помощью массивов
A:1 2 3 4 5 6 7 8 9 100 1 1 2 2 5 5 5 3 3
A[i]=j ⇒ j родитель i ; A[i]=0 ⇒ i корень11
Представление деревьев с помощью указателей
12
Реализация деревьев с помощью указателей
1 class PointerTree<T> implements Tree<T> {2 private T data;3 private Tree<T> parent;4 private Tree<T> leftMostChild;5 private Tree<T> rightMostChild;6 private Tree<T> leftSibling;7 private Tree<T> rightSibling;8 ...9 }
13
АТД Бинарное дерево
1 interface BinaryTree<T> {2 T getData();3 void setData(T o);4
5 BinaryTree<T> getParent();6 void setParent(BinaryTree<T> parent);7
8 void setLeft(BinaryTree<T> value);9 BinaryTree<T> getLeft();10
11 void setRight(BinaryTree<T> value);12 BinaryTree<T> getRight();13 }
14
Представление бинарных деревьев с помощью масси-вов
A:1 2 3 4 5 6 7a b c d e f g
A[i] является родителем для A[2*i] и A[2*i+1], где A[2*i] иA[2*i+1] левый и правый ребенок соответственно.
15
Реализация бинарных деревьев с помощью указателей
1 class BinaryTreeImpl<T> implements BinaryTree<T> {2 BinaryTree<T> parent;3 BinaryTree<T> left;4 BinaryTree<T> right;5 T data;6 }
16
Применение бинарных деревьев: кодирование и сжатие
Символ Код №1 Код №2a 000 000b 001 11c 010 01d 011 001e 100 10
bcd ⇒ 001 010 011 (Код №1) ⇒ 11 01 001 (Код №2)
17
Префиксный код в теории кодирования — код со словом пе-ременной длины, имеющий такое свойство: если в код входитслово a, то для любой непустой строки b слова ab в коде несуществует. Хотя префиксный код состоит из слов разнойдлины, эти слова можно записывать без разделительногосимвола.
Идея сжатия: использовать для чаще встречающихся сим-волов(слов) кодовые слова меньшей длинны, чем для режевстречающихся.
В задаче построения префиксного кода для символов опре-деленной строки даны символы строки и их вероятность.
Как построить?18
Алгоритм Хаффмана
19
Алгоритм Хаффмана
1. Пока ∃ >1 дерева в лесу
2. i = идекс дерева с наименьшим весом, j = идекс деревасо вторым наименьшим весом
3. Создаем новый узел с левым сыном i и правым сыном j
4. Заменяем в лесу i-е дерево новым деревом и ставим емувес как сумму весов i-го и j-го деревьев
5. Удаляем j-е дерево
20
Реализация леса для алгоритма Хаффмана
1 class HaffmanTree extends BinaryTreeImpl<String> {2 public double weight;3
4 public HaffmanTree(String str, double weight) {5 super(str);6 this.weight = weight;7 }8 }9
10 HaffmanTree[] forest = new HaffmanTree[MAX_COUNT];11 int forestLength = 0;
21
Основной цикл алгоритма Хаффмана
1 length=forestLength;2 while (length > 1) {3 swapInForest(getIndexWithMinWeight(), length-1);4 forestLength--;5 int min = getIndexWithMinWeight();6 HaffmanTree newTree = new HaffmanTree(7 forest[min].getData()+forest[length].getData(),8 forest[min].weight + forest[length].weight);9 newTree.setLeft(forest[min]);10 newTree.setRight(forest[length]);11 forest[min] = newTree;12 }
22
Список литературы
• Ахо А., Хопкрофт Д., Ульман Д. Структуры данных иалгоритмы. - М. : Издательский дом “Вильямс”, 2000.сс.77-102.
• Кормен Т., Лейзерсон Ч., Ривест Р., Штайн К. Алгорит-мы: построение и анализ, 2-е издание. - М. : Издатель-ский дом “Вильямс”, 2007. сс.274-281, 459-467.
• Кнут Д, Искусство программирования, том 1. Основныеалгоритмы, 3-е изд. - М. : Издательский дома “Вильямс”,2000. сс.352-475.
23
Top Related