
- •Введение
- •Основные понятия и определения
- •Типы данных
- •1.1.1. Понятие типа данных
- •1.2.2. Внутреннее представление базовых типов в оперативной памяти
- •1.2.2. Внутреннее представление структурированных типов данных
- •1.2.3. Статическое и динамическое выделение памяти
- •Абстрактные типы данных (атд)
- •Понятие атд
- •1.2.2. Спецификация и реализация атд
- •Структуры данных
- •1.3.1. Понятие структуры данных
- •1.3.2. Структуры хранения — непрерывная и ссылочная
- •1.4.3. Классификация структур данных
- •Алгоритмы
- •1.4.1. Понятие алгоритма
- •1.4.2. Способы записи алгоритмов.
- •1.4.3. Введение в анализ алгоритмов Вычислительные модели
- •Задача анализа алгоритмов
- •Время работы алгоритма
- •Время выполнения в худшем и среднем случае
- •1.4.3. Введение в рекурсию
- •Первые примеры
- •1.5.1. Введение в «длинную» арифметику
- •1.5.2. Рекурсия
- •1.5.3. Поразрядные операции. Реализация атд «Множество»
- •2. Линейные структуры данных
- •2.1. Атд "Стек", "Очередь", "Дек"
- •2.2. Реализация стеков
- •2.2.1. Непрерывная реализация стека с помощью массива
- •2.2.2. Ссылочная реализация стека в динамической памяти
- •2.2.3. Примеры программ с использованием стеков
- •2.3. Реализация очередей
- •2.3.2. Непрерывная реализация очереди с помощью массива
- •2.3.2. Ссылочная реализация очереди в динамической памяти
- •2.3.3. Ссылочная реализация очереди с помощью циклического списка
- •2.3.4. Очереди с приоритетами
- •2.3.5. Пример программы с использованием очереди
- •2.4. Списки как абстрактные типы данных
- •2.4.1. Модель списка с выделенным текущим элементом
- •2.4.2. Однонаправленный список (список л1)
- •2.4.3. Двунаправленный список (список л2)
- •2.4.4. Циклический (кольцевой) список
- •2.5. Реализация списков с выделенным текущим элементом
- •2.5.1. Однонаправленные списки Ссылочная реализация в динамической памяти на основе указателей
- •2.5.2. Двусвязные списки
- •2.5.3. Кольцевые списки
- •2.5.4. Примеры программ, использующих списки Очередь с приоритетами на основе линейного списка
- •Задача Иосифа (удаление из кольцевого списка)
- •2.6. Рекурсивная обработка линейных списков
- •2.6.1. Модель списка при рекурсивном подходе
- •2.6.2. Реализация линейного списка при рекурсивном подходе
- •3. Иерархические структуры данных
- •3.1. Иерархические списки
- •3.1.1 Иерархические списки как атд
- •3.1.2. Реализация иерархических списков
- •3.2. Деревья и леса
- •3.2.1. Определения
- •3.2. Способы представления деревьев
- •3.2.3. Терминология деревьев
- •3.2.4. Упорядоченные деревья и леса. Связь с иерархическими списками
- •3.3. Бинарные деревья
- •3.3.1. Определение. Представления бинарных деревьев
- •3.3.2. Математические свойства бинарных деревьев
- •3.4. Соответствие между упорядоченным лесом и бинарным деревом
- •3.5. Бинарные деревья как атд
- •3.6. Ссылочная реализация бинарных деревьев
- •3.6.1. Ссылочная реализация бинарного дерева на основе указателей
- •3.6.2. Ссылочная реализация на основе массива
- •3.6.3. Пример — построение дерева турнира
- •3.7. Обходы бинарных деревьев и леса
- •3.7.1. Понятие обхода. Виды обходов
- •3.7.2. Рекурсивные функции обхода бинарных деревьев
- •3.7.3. Нерекурсивные функции обхода бинарных деревьев
- •3.7.4. Обходы леса
- •3.7.5. Прошитые деревья
- •3.8. Применения деревьев
- •3.8.1. Дерево-формула
- •3.8.2. Задача сжатия информации. Коды Хаффмана
- •4. Сортировка и родственные задачи
- •4.1. Общие сведения
- •4.1.1. Постановка задачи
- •4.1.2. Характеристики и классификация алгоритмов сортировки
- •4.2. Простые методы сортировки
- •4.2.1. Сортировка выбором
- •4.2.2. Сортировка алгоритмом пузырька
- •4.2.3.Сортировка простыми вставками.
- •4.3. Быстрые способы сортировки, основанные на сравнении
- •4.3.1. Сортировка упорядоченным бинарным деревом
- •Анализ алгоритма сортировки бинарным деревом поиска
- •4.3.2. Пирамидальная сортировка
- •Первая фаза сортировки пирамидой
- •Вторая фаза сортировки пирамидой
- •Анализ алгоритма сортировки пирамидой
- •Реализация очереди с приоритетами на базе пирамиды
- •4.3.2. Сортировка слиянием
- •Анализ алгоритма сортировки слиянием
- •4.3.3. Быстрая сортировка Хоара
- •Анализ алгоритма быстрой сортировки
- •4.3.4. Сортировка Шелла
- •4.3.5. Нижняя оценка для алгоритмов сортировки, основанных на сравнениях
- •4.4. Сортировка за линейное время
- •4.4.1. Сортировка подсчетом
- •4.4.2. Распределяющая сортировка от младшего разряда к старшему
- •4.4.3. Распределяющая сортировка от старшего разряда к младшему
- •5. Структуры и алгоритмы для поиска данных
- •5.1. Общие сведения
- •5.1.1. Постановка задачи поиска
- •5.1.2. Структуры для поддержки поиска
- •5.1.3. Соглашения по программному интерфейсу
- •5.2. Последовательный (линейный) поиск
- •5.3. Бинарный поиск в упорядоченном массиве
- •5.4. Бинарные деревья поиска
- •5.4.1. Анализ алгоритмов поиска, вставки и удаления Поиск
- •Вставка
- •Удаление
- •5.4.3. Реализация бинарного дерева поиска
- •5.5. Сбалансированные деревья
- •Определение и свойства авл-деревьев
- •Вращения
- •Алгоритмы вставки и удаления
- •Реализация рекурсивного алгоритма вставки в авл-дерево
- •5.5.2. Сильноветвящиеся деревья
- •Бинарные представления сильноветвящихся деревьев
- •5.5.3. Рандомизированные деревья поиска
- •5.6. Структуры данных, основанные на хеш-таблицах
- •5.6.2. Выбор хеш-функций и оценка их эффективности
- •Модульное хеширование (метод деления)
- •Мультипликативный метод
- •Метод середины квадрата
- •5.6.2. Метод цепочек
- •5.6.3. Хеширование с открытой адресацией
- •5.6.4. Пример решения задачи поиска с использованием хеш-таблицы
Вращения
Вращениями называются такие изменения структуры дерева, которые не меняют содержащуюся в нем информацию и не нарушают упорядоченности, но приводят к более сбалансированной структуре. Иными словами, после выполнения вращения последовательность, полученная при помощи ЛКП обхода дерева, не должна измениться.
Для балансировки АВЛ-дерева используют четыре вида вращений: левое и правое малые вращения затрагивают два узла вместе с их поддеревьями, левое и правое большое вращения затрагивают три узла с их поддеревьями. Большие вращения представляют собой комбинацию двух малых, поэтому их иногда называют комбинированными или двукратными (а малые — однократными).
Начнем с малых вращений. Сначала рассмотрим примеры. На рис.5.6 показано дерево всего с двумя узлами (узел 7 является правым сыном узла 5). Ясно, что поворот рисунка не нарушил упорядоченности дерева, но изменил его структуру. Теперь узел 5 стал левым сыном узла 7. Такое преобразование называется малым правым вращением (понятия левое и правое в данном случае весьма условны, мы пользуемся терминологией из [Вирт, Шень]). Если на рис.5.6 изменить направление стрелки, то будем иметь левое малое вращение.
Рис.5.6. Простой пример малого правого вращения
Однако в данном случае никакой необходимости во вращении не было, так как дерево из двух узлов всегда сбалансировано. Поэтому усложним пример — нарушен баланс в узле 5 (рис.5.7). Сбалансированность можно восстановить при помощи малого правого вращения для узлов 5 и 7, как на предыдущем рисунке, при этом получим идеально сбалансированное дерево. Из данного примера понятно, что вращение не сводится к простому повороту рисунка, поскольку левое поддерево узла 7 стало теперь правым поддеревом узла 5.
Рис.5.7. Восстановление сбалансированности при помощи малого правого вращения
Сформулируем правило малого правого вращения. Пусть вершина a имеет правого сына b . Обозначим через P левое поддерево вершины a, через Q и R — левое и правое поддеревья вершины b (рис.5.8). Упорядоченность дерева требует выполнения условия P<a<Q<b<R. Точно того же требует упорядоченность дерева с корнем b, которое изображено на рисунке справа. Поэтому данное преобразование не нарушает упорядоченности дерева, но уменьшает на единицу его высоту, что нам и нужно. Аналогично выполняется малое левое вращение.
Рис.5.8. Общее правило для малого правого вращения
Кроме малых вращений в АВЛ-дереве используются еще большие вращения, которые затрагивают три узла дерева с их поддеревьями. Сначала простой пример — дерево из трех узлов (рис.5.9), у которого нарушенный баланс узла 4, восстанавливается с помощью большого правого вращения.
Рис.5.9. Простой пример большого правого вращения
Из этого примера видно, что фактически большое вращение— это два малых (левое и правое), выполненных одно за другим. Теперь более сложный пример (рис.5.10), из которого видно, как перемещаются поддеревья. Обратим внимание, что опять полностью восстановили сбалансированность.
Рис.5.10. Более сложный пример большого правого вращения
Общее правило показано на рис.5.11. Аналогично определяется большое левое вращение — достаточно поменять направление стрелки на рис.5.11.
Рис.5.11. Общее правило большого правого вращения
Доказано, что рассмотренных выше четырех вариантов вращения достаточно для того, чтобы при выполнении вставок и удалений элементов все время поддерживать дерево в сбалансированном состоянии.
Например, рассмотрим процесс построения АВЛ-дерева из последовательности элементов 4 5 7 2 1 3 6 (данный пример приводится в [4] и хорош тем, что позволяет продемонстрировать все четыре вида вращений). Если использовать обычный алгоритм вставки каждого узла в качестве листа бинарного дерева поиска, то получим дерево, изображенное на рис. 5.12.
Рис.5.12. Бинарное дерево поиска, построенное при помощи обычного алгоритма вставки
Данное дерево не сбалансировано в узлах 2 и 5, его высота равна трем. Попробуем построить из этой же последовательности сбалансированное дерево высоты 2, используя вращения. Процесс построения дерева изображен на рис.5.13, пунктирная связь проведена к тому узлу, который добавляется на каждом этапе.
а) добавление одного элемента к корню не может нарушить упорядоченности
б) теперь корень(4) не сбалансирован— выполнили малое правое вращение (узлы 4 и 5)
в)сбалансированность
не нарушилась
г) выполнили малое левое вращение (узлы 4 и 2)
д) выполнили большое левое вращение (узлы 5, 2 и 4)
е) выполнили большое правое вращение (узлы 5,7 и 6)
Рис.5.13. Последовательность построения АВЛ-дерева из значений 4 5 7 2 1 3 6.
Теперь дерево полностью сбалансировано, а высота его равна двум. Интересно, что в данном случае удалось получить полное бинарное дерево (все листья в одном нижнем уровне), поскольку количество узлов равно 7. При произвольных данных результат был бы несколько хуже.
Теперь обсудим в общих чертах алгоритмы вставки и удаления элементов. Алгоритм поиска в АВЛ-дереве полностью совпадает с алгоритмом для обычного бинарного дерева, обеспечивая при сбалансированной структуре логарифмическую сложность от числа узлов в любом случае.