Основы программирования — второй семестр 08-09; Михалкович С.С.; IV часть — различия между версиями

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск
(Деревья)
(Порядки обхода деревьев)
Строка 61: Строка 61:
 
}}
 
}}
  
===Порядки обхода деревьев===
+
=== Порядки обхода деревьев ===
 +
Требуется составить алгоритм, обходящий все узлы дерева в некотором порядке. <br />
 +
Существует несколько вариантов обходов, каждый из которых описывается рекурсивным алгоритмом.
  
* Инфиксный (левое, корень, правое)
+
Рассмотрим эти алгоритмы для ''обычного'' и ''бинарного'' деревьев: <br />
* Префиксный (корень, левое, правое)
+
[[Изображение:TreeForOrder.png|300px|Дерево]] &nbsp;&nbsp;&nbsp; [[Изображение:BinTreeForOrder.png|230px|Бинарное дерево разбора выражений]]
* Постфиксный (левое, правое, корень)
+
 
 +
 
 +
* '''''Инфиксный'''''
 +
: <tt>Д<sub>1</sub> К Д<sub>2</sub> Д<sub>1</sub> К Д<sub>3</sub> К ... К Д<sub>n</sub></tt>
 +
: и
 +
: БД: <tt>Левое_поддерево Корень Правое_поддерево</tt>
 +
 
 +
* '''''Префиксный'''''
 +
: <tt>К Д<sub>1</sub> Д<sub>2</sub> Д<sub>1</sub> Д<sub>3</sub> ... Д<sub>n</sub></tt>
 +
: и
 +
: БД: <tt>Корень Левое_поддерево Правое_поддерево</tt>
 +
:: <tt>'''+ * a b c'''</tt> — '''префиксная''' запись выражения
 +
 
 +
: '''Примечание.''' Для вычисления выражений, записанных в ''префиксной'' записи, применяется ''рекурсивный'' алгоритм.
 +
 
 +
* '''''Постфиксный'''''
 +
: <tt>Д<sub>1</sub> Д<sub>2</sub> Д<sub>1</sub> Д<sub>3</sub> ... Д<sub>n</sub> К</tt>
 +
: и
 +
: БД: <tt>Левое_поддерево Правое_поддерево Корень </tt>
 +
:: <tt>'''a b * с +'''</tt> — '''обратная польская безскобочная''' запись выражения
 +
{{Hider
 +
|title = Обратная польская запись
 +
|content =
 +
:Или '''Обратная польская нотация (ОПН)''' ''(Обратная бесскобочная запись (ОБЗ), Постфиксная нотация, Бесскобочная символика Лукашевича, Польская инверсная запись, Полиз)'' — <br>форма записи математических выражений, в которой операнды расположены перед знаками операций.
 +
 
 +
Обратная польская нотация была разработана австралийским философом и специалистом в области теории вычислительных машин ''Чарльзом Хэмблином'' в середине 1950-х на основе польской нотации, которая была предложена в 1920 году польским математиком ''Яном Лукасевичем''. Работа Хэмблина была представлена на конференции в июне 1957, и издана в 1957 и 1962.
 +
 
 +
Подробнее см. [http://ru.wikipedia.org/wiki/Обратная_польская_запись Википедию]
 +
}}
  
 
===Задачи на бинарные деревья===
 
===Задачи на бинарные деревья===

Версия 15:58, 31 марта 2009


Лекция 8

Деревья

Деревом назовем совокупность узлов, называемых вершинами дерева, соединенных между собой ребрами, называемыми ветвями.
Tree.png
Количество уровней называется глубиной дерева.
Каждая вершина нижнего уровня соединяется ровно с одной вершиной предыдущего уровня.

Единственная вершина на уровне 0 называется корнем дерева.
Она не имеет вершин-предков.

Вершины, не имеющие потомков, называют листьями дерева, а совокупность всех листьев образует крону дерева.

Примеры.

  • Дерево папок на диске
    Дерево папок.png
  • Самый очевидный пример — генеалогическое древо
    Генеалогическое-дерево.gif
  • Главы и пункты книги
    Содержание книги.jpg
  • Дерево разбора выражений
a*b + c*d

Дерево выражения2.png

Теперь дадим рекурсивное определение дерева:

Дерево ::= корень список_поддеревьев
         | ε 
Список поддеревьев ::= список_поддеревьев дерево
                     | ε
// ε означает «пусто»

Дерево называется бинарным (двоичным), если каждая его вершина имеет не более двух потомков.
(Далее бинарные деревья будем сокращать как БД)

Двоичное_дерево  ::= корень левое_поддерево правое_поддерево
                  | ε
Левое_поддерево  ::= двоичное_дерево
Правое_поддерево ::= двоичное_дерево

БД называется идеально сбалансированным, если для каждого узла количество узлов в его правом поддереве отличается от количества узлов в его левом поддереве максимум на единицу. <здесь будут рисунки деревьев>

Полным называют БД, у которого каждая вершина, не являющаяся листом, имеет ровно двух потомков, и все листья находятся на последнем уровне.


Нетрудно заметить, что количество узлов (u) и количество ребер (v) связаны простой формулой: <math>u = v + 1</math>.

Количество узлов в полном БД высчитывается по формуле
<math>\ 2^{n+1} - 1</math>

Порядки обхода деревьев

Требуется составить алгоритм, обходящий все узлы дерева в некотором порядке.
Существует несколько вариантов обходов, каждый из которых описывается рекурсивным алгоритмом.

Рассмотрим эти алгоритмы для обычного и бинарного деревьев:
Дерево     Бинарное дерево разбора выражений


  • Инфиксный
Д1 К Д2 Д1 К Д3 К ... К Дn
и
БД: Левое_поддерево Корень Правое_поддерево
  • Префиксный
К Д1 Д2 Д1 Д3 ... Дn
и
БД: Корень Левое_поддерево Правое_поддерево
+ * a b cпрефиксная запись выражения
Примечание. Для вычисления выражений, записанных в префиксной записи, применяется рекурсивный алгоритм.
  • Постфиксный
Д1 Д2 Д1 Д3 ... Дn К
и
БД: Левое_поддерево Правое_поддерево Корень
a b * с +обратная польская безскобочная запись выражения

Задачи на бинарные деревья

Класс TreeNode<T>

Создание идеально сбалансированного дерева.

Вывод узлов дерева в инфиксном, префиксном, постфиксном порядке.

Связь деревьев и рекурсии.

Определение глубины дерева.

Количество листов в дереве.

Поиск элемента в дереве.

Бинарные деревья поиска

Определение БДП.

Добавление в БДП. Инвариантность БДП относительно операции добавления.

Оценка количества операций при добавлении. Худший случай.

Сортировка деревом. Асимптотическая сложность алгоритма.

Поиск элемента в БДП.

Произвольные деревья

TreeNode = class
  data: integer;
  leftChild, rightSibling: TreeNode;
end;
function CreateRandomTree(n: integer; m: integer): TreeNode;  
// n - количество сыновей, m - количество уровней
begin
  Result := nil;
  if m=0 then exit;
  for var i:=1 to n do
    Result := new TreeNode(Random(100), CreateRandomTree(Random(1,5), m-1), Result)
end;
root := CreateRandomTree(3,4);
root := new TreeNode(Random(100), root, nil);
procedure PrintTree(r: TreeNode);
begin
  while r<>nil do
  begin
    write(r.data,' ');
    PrintTree(r.leftChild);
    r := r.rightSibling;
  end
end;