- •Структуры и алгоритмы обработки данных
- •Алгоритмы. Основные определения
- •От задачи к программе
- •Написание программы.
- •Типы данных, структуры данных и абстрактные типы данных
- •Указатели и курсоры
- •Время выполнения программ
- •Измерение времени выполнения программы
- •Степень (порядок) роста
- •Вычисление времени выполнения программ
- •Линейные абстрактные типы данных атд «Список»
- •Реализация списков посредством массивов
- •Реализация списков с помощью указателей
- •Атд «Стек»
- •Атд «Очередь»
- •Реализация очередей с помощью циклических массивов
- •Нелинейные абстрактные типы данных Деревья
- •Порядок узлов
- •Прямой, обратный и симметричный обходы дерева
- •Помеченные деревья и деревья выражений
- •Представление деревьев с помощью массивов
- •Специальные виды множеств атд “Дерево двоичного поиска”
- •Атд "Словарь", основанный
- •Представление ориентированных графов
- •Атд для ориентированных графов
- •Задача нахождения кратчайшего пути
- •Int **c, // массив стоимостей
- •Int *d) // массив кратчайших
- •Остовные деревья минимальной стоимости
- •Обход графов
- •Поиск в ширину
- •Поиск в глубину
- •Сортировка
- •Простые схемы сортировки Метод «пузырька»
- •Сортировка вставками
- •Быстрая сортировка
- •Пирамидальная сортировка
- •«Карманная» сортировка
- •Порядковые статистики
- •Методы разработки алгоритмов. Типы алгоритмов
- •Алгоритмы «разделяй и властвуй» (метод декомпозиции)
- •Баланс подзадач
- •Динамическое программирование
- •Перемножение нескольких матриц
- •Шаг 1: строение оптимальной расстановки скобок
- •Шаг 2: рекуррентное соотношение
- •Шаг 3: вычисление оптимальной стоимости
- •Void MatrixChainOrder(int n, // кол-во матриц
- •Int p[], // размеры матриц
- •Int **s) // оптимальное k
- •Шаг 4: построение оптимального решения
- •Int **s, // таблица, полученная
- •Int I, // индексы
- •Когда применимо динамическое программирование?
- •Оптимальность для подзадач
- •Перекрывающиеся подзадачи
- •«Жадные» алгоритмы
- •"Жадные" алгоритмы как эвристики
- •Когда применим жадный алгоритм?
- •Принцип жадного выбора
- •Оптимальность для подзадач
- •Поиск с возвратом
- •Функции выигрыша
- •Метод ветвей и границ
- •Структуры данных и алгоритмы для внешней памяти
- •Внешняя сортировка
- •Хранение данных в файлах
- •Простая организация данных
- •Хешированные файлы
- •Индексированные файлы
- •Содержание
- •Глава I. Линейные абстрактные типы данных 31
- •Глава II. Сортировка 108
Порядок узлов
С ыновья узла обычно упорядочиваются слева направо. Поэтому два дерева на рис. различны, так как порядок сыновей различен.
Если порядок сыновей игнорируется, то такое дерево называется неупорядоченным, в противном случае дерево называется упорядоченным.
Упорядочивание слева направо сыновей («родных детей» одного узла) можно использовать для сопоставления узлов, которые не связаны отношениями предки-потомки.
Соответствующее правило звучит следующим образом: если узлы а и b являются сыновьями одного родителя и узел а лежит слева от узла b, то все потомки узла а будут находиться слева от любых потомков узла b.
Узел 8 расположен справа от узла 2, слева от узлов 9,6,10,4, 7 и не имеет отношений справа-слева относительно предков 1,3, 5.
Прямой, обратный и симметричный обходы дерева
Существует несколько способов обхода (прохождения) всех узлов дерева. Три наиболее часто используемых это: обход в прямом порядке, обход в обратном порядке и обход во внутреннем порядке (также этот вид обхода называют симметричным).
Все три способа рекурсивно можно определить следующим образом:
-
Если дерево Т является нулевым деревом, то в список обхода заносится пустая запись.
-
Если дерево Т состоит из одного узла, то в список обхода заносится этот узел.
-
Далее, пусть Т – дерево с корнем n и поддеревьями Т1,Т2,…, Тк, тогда для различных способов обхода имеем:
-
При прохождении в прямом порядке узлов дерева Т сначала посещается корень n, затем узлы поддерева Т1, далее все узлы поддерева Т2, и т.д. Последними посещаются узлы поддерева Тк.
-
При симметричном обходе узлов сначала посещаются в симметричном порядке все узлы поддерева Т1, далее корень n, затем последовательно в симметричном порядке все узлы поддеревьев Т2,…,Тк.
-
Во время обхода в обратном порядке сначала посещаются все узлы поддерева Т1, затем последовательно посещаются все узлы поддеревьев Т2,…,Тк, также в обратном порядке, последним посещается корень n.
Пример. Сделаем обход дерева в прямом порядке.
С начала посетим узел 1, затем рассмотрим поддерево 2, оно состоит из одного узла, который мы и записываем. Далее обходим второе поддерево с корнем 3. Записываем узел 3 и для него рассматриваем первое поддерево с корнем 5, потом получаем узлы 8 и 9. Продолжая этот процесс, получим полный список узлов, получаемых при прохождении в прямом порядке исходного дерева: 1,2,3,5,8,9,6,10,4,7.
Сделаем обход дерева в обратном порядке. В этом случае сначала посещаются все узлы поддерева 2, затем все узлы поддерева с корнем 3 в обратном порядке. Получим 2,8,9,5,10, 6,3,7,4,1.
При прохождении узлов дерева в симметричном порядке получим:
2, 1, 8,5,9,3,10,6,7,4.
Помеченные деревья и деревья выражений
Часто бывает полезным сопоставить каждому узлу дерева метку или значение. Такое дерево называется помеченным. Метка узла это не «имя» узла, а значение, которое хранится в узле.
Можно провести такую аналогию: дерево–список, узел–позиция, метка–элемент.
Пример.
На рис. показано дерево с метками, представляю-щее арифметическое выражение (a+b)*(a+c), где n1,n2,…,n7 – имена узлов (метки на рис. проставлены рядом с соответствующими узлами).
Правила соответствия меток элементам выражений следующие:
-
Метка каждого листа соответствует операнду и содержит его значение, например узел n4 представляет операнд а.
-
Метка каждого родительского узла соответствует оператору.
Часто при обходе деревьев составляется список не имен узлов, а их меток. В случае дерева выражений при прямом обходе получаем известную префиксную форму выражений, где оператор предшествует и левому и правому операндам.
* (+ a b) (+ a c)
Обратное упорядочивание меток дерева выражений дает так называемое постфиксное (или польское) представление выражений. Эти представления удобны тем, что при их написании нет необходимости использовать скобки.
a b + a c + *
При симметричном обходе дерева выражений получается инфиксная форма выражения, которая совпадает с привычной «стандартной» формой записи выражений.
Для формирования АТД на основе математического определения дерева мы должны задать множество операторов, выполняемых над объектами типа TREE (дерево).
Рассмотрим следующие операторы:
-
PARENT(n,T) возвращает родителя узла n в дереве Т. Если n является корнем, то возвращается Л.
Л – нулевой узел, указывающий на то, что мы выходим за пределы дерева.
-
LEFTMOST_CHILD(n,T) возвращает самого левого сына узла n в дереве Т. Если n является листом, то возвращается Л.
-
RIGHT_SIBLING(n,T) возвращает правого брата узла n в дереве Т и значение Л если такового не существует. Для нахождения правого брата сначала находится родитель р узла n и все сыновья узла р, затем среди этих сыновей находится узел, расположенный непосредственно справа от узла n.
-
LABEL(n,T) возвращает метку узла n дерева Т. Для выполнения этой функции требуется, чтобы на узлах дерева были определены метки.
-
CREATEi(v,T1, T2,…, Ti) – это обширное семейство “созидающих” функций, которые для каждого i=0,1,2,… создают новый корень r с меткой v и далее для этого корня создает i сыновей, которые становятся сыновьями поддеревьев T1, T2,…, Ti. Эти функции возвращают дерево с корнем r. Если i=0, то возвращается один узел r, который одновременно является и корнем и листом.
-
ROOT(T) возвращает узел, являющийся корнем дерева Т. Если Т – пустое дерево, то возвращается Л.
-
MAKENULL(T) Этот оператор делает дерево Т пустым деревом.