- •Глава 1. Основные понятия 14
- •Глава 2. Списки 30
- •Глава 3. Стеки и очереди 59
- •Глава 4. Массивы 74
- •Глава 5. Рекурсия 86
- •Глава 6. Деревья 121
- •Глава 7. Сбалансированные деревья 153
- •Глава 8. Деревья решений 180
- •Глава 9. Сортировка 213
- •Введение
- •Целевая аудитория
- •Глава 1. Основные понятия
- •Что такое алгоритмы?
- •Анализ скорости выполнения алгоритмов
- •Пространство — время
- •Оценка с точностью до порядка
- •Поиск сложных частей алгоритма
- •Сложность рекурсивных алгоритмов
- •Многократная рекурсия
- •Косвенная рекурсия
- •Требования рекурсивных алгоритмов к объему памяти
- •Наихудший и усредненный случай
- •Часто встречающиеся функции оценки порядка сложности
- •Логарифмы
- •Реальные условия — насколько быстро?
- •Обращение к файлу подкачки
- •Псевдоуказатели, ссылки на объекты и коллекции
- •Коллекции
- •Вопросы производительности
- •Глава 2. Списки
- •Знакомство со списками
- •Простые списки
- •Коллекции
- •Список переменного размера
- •Класс SimpleList
- •Неупорядоченные списки
- •Связные списки
- •Добавление элементов к связному списку
- •Удаление элементов из связного списка
- •Уничтожение связного списка
- •Сигнальные метки
- •Инкапсуляция связных списков
- •Доступ к ячейкам
- •Разновидности связных списков
- •Циклические связные списки
- •Проблема циклических ссылок
- •Двусвязные списки
- •Другие связные структуры
- •Псевдоуказатели
- •Глава 3. Стеки и очереди
- •Множественные стеки
- •Очереди
- •Циклические очереди
- •Очереди на основе связных списков
- •Применение коллекций в качестве очередей
- •Приоритетные очереди
- •Многопоточные очереди
- •Модель очереди
- •Глава 4. Массивы
- •Треугольные массивы
- •Диагональные элементы
- •Нерегулярные массивы
- •Прямая звезда
- •Нерегулярные связные списки
- •Разреженные массивы
- •Индексирование массива
- •Очень разреженные массивы
- •Глава 5. Рекурсия
- •Что такое рекурсия?
- •Рекурсивное вычисление факториалов
- •Анализ времени выполнения программы
- •Рекурсивное вычисление наибольшего общего делителя
- •Анализ времени выполнения программы
- •Рекурсивное вычисление чисел Фибоначчи
- •Анализ времени выполнения программы
- •Рекурсивное построение кривых Гильберта
- •Анализ времени выполнения программы
- •Рекурсивное построение кривых Серпинского
- •Анализ времени выполнения программы
- •Опасности рекурсии
- •Бесконечная рекурсия
- •Потери памяти
- •Необоснованное применение рекурсии
- •Когда нужно использовать рекурсию
- •Хвостовая рекурсия
- •Нерекурсивное вычисление чисел Фибоначчи
- •Устранение рекурсии в общем случае
- •Нерекурсивное построение кривых Гильберта
- •Нерекурсивное построение кривых Серпинского
- •Глава 6. Деревья
- •Определения
- •Представления деревьев
- •Полные узлы
- •Списки потомков
- •Представление нумерацией связей
- •Полные деревья
- •Обход дерева
- •Упорядоченные деревья
- •Добавление элементов
- •Удаление элементов
- •Обход упорядоченных деревьев
- •Деревья со ссылками
- •Работа с деревьями со ссылками
- •Квадродеревья
- •Изменение max_per_node
- •Использование псевдоуказателей в квадродеревьях
- •Восьмеричные деревья
- •Глава 7. Сбалансированные деревья
- •Сбалансированность дерева
- •Авл‑деревья
- •Вращения авл‑деревьев
- •Правое вращение
- •Левое вращение
- •Вращение влево‑вправо
- •Вращение вправо‑влево
- •Вставка узлов на языке Visual Basic
- •Удаление узла из авл‑дерева
- •Левое вращение
- •Вращение вправо‑влево
- •Другие вращения
- •Реализация удаления узлов на языке Visual Basic
- •Б‑деревья
- •Производительность б‑деревьев
- •Вставка элементов в б‑дерево
- •Удаление элементов из б‑дерева
- •Разновидности б‑деревьев
- •Нисходящие б‑деревья
- •Улучшение производительности б‑деревьев
- •Балансировка для устранения разбиения блоков
- •Добавление свободного пространства
- •Вопросы, связанные с обращением к диску
- •Псевдоуказатели
- •Выбор размера блока
- •Кэширование узлов
- •Глава 8. Деревья решений
- •Поиск в деревьях игры
- •Минимаксный поиск
- •Улучшение поиска в дереве игры
- •Предварительное вычисление начальных ходов
- •Определение важных позиций
- •Эвристики
- •Поиск в других деревьях решений
- •Метод ветвей и границ
- •Эвристики
- •Восхождение на холм
- •Метод наименьшей стоимости
- •Сбалансированная прибыль
- •Случайный поиск
- •Последовательное приближение
- •Момент остановки
- •Локальные оптимумы
- •Алгоритм «отжига»
- •Сравнение эвристик
- •Другие сложные задачи
- •Задача о выполнимости
- •Задача о разбиении
- •Задача поиска Гамильтонова пути
- •Задача коммивояжера
- •Задача о пожарных депо
- •Краткая характеристика сложных задач
- •Глава 9. Сортировка
- •Общие соображения
- •Объединение и сжатие ключей
- •Примеры программ
- •Сортировка выбором
- •Рандомизация
- •Сортировка вставкой
- •Вставка в связных списках
- •Пузырьковая сортировка
- •Быстрая сортировка
- •Сортировка слиянием
- •Пирамидальная сортировка
- •Пирамиды
- •Приоритетные очереди
- •Анализ пирамид
- •Алгоритм пирамидальной сортировки
- •Сортировка подсчетом
- •Блочная сортировка
- •Блочная сортировка с применением связного списка
- •Блочная сортировка на основе массива
- •Глава 10. Поиск
- •Примеры программ
- •Поиск методом полного перебора
- •Поиск в упорядоченных списках
- •Поиск в связных списках
- •Двоичный поиск
- •Интерполяционный поиск
- •Строковые данные
- •Следящий поиск
- •Интерполяционный следящий поиск
- •Глава 11. Хеширование
- •Связывание
- •Преимущества и недостатки связывания
- •Хранение хеш‑таблиц на диске
- •Связывание блоков
- •Удаление элементов
- •Преимущества и недостатки применения блоков
- •Открытая адресация
- •Линейная проверка
- •Первичная кластеризация
- •Упорядоченная линейная проверка
- •Квадратичная проверка
- •Псевдослучайная проверка
- •Удаление элементов
- •Рехеширование
- •Изменение размера хеш‑таблиц
- •Глава 12. Сетевые алгоритмы
- •Определения
- •Представления сети
- •Оперирование узлами и связями
- •Обходы сети
- •Наименьшие остовные деревья
- •Кратчайший маршрут
- •Установка меток
- •Варианты метода установки меток
- •Коррекция меток
- •Варианты метода коррекции меток
- •Другие задачи поиска кратчайшего маршрута
- •Двухточечный кратчайший маршрут
- •Вычисление кратчайшего маршрута для всех пар
- •Штрафы за повороты
- •Небольшое число штрафов за повороты
- •Большое число штрафов за повороты
- •Применения метода поиска кратчайшего маршрута
- •Разбиение на районы
- •Составление плана работ с использованием метода критического пути
- •Планирование коллективной работы
- •Максимальный поток
- •Приложения максимального потока
- •Непересекающиеся пути
- •Распределение работы
- •Глава 13. Объектно‑ориентированные методы
- •Преимущества ооп
- •Инкапсуляция
- •Обеспечение инкапсуляции
- •Полиморфизм
- •Зарезервированное слово Implements
- •Наследование и повторное использование
- •Парадигмы ооп
- •Управляющие объекты
- •Контролирующий объект
- •Итератор
- •Дружественный класс
- •Интерфейс
- •Порождающий объект
- •Единственный объект
- •Преобразование в последовательную форму
- •Парадигма Модель/Вид/Контроллер.
- •Контроллеры
- •Виды/Контроллеры
- •Требования к аппаратному обеспечению
- •Выполнение программ примеров
Глава 8. Деревья решений
Многие сложные реальные задачи можно смоделировать при помощи деревьев решений (decision trees). Каждый узел дерева представляет один шаг решения задачи. Каждая ветвь в дереве представляет решение, которое ведет к более полному решению. Листья представляют собой окончательное решение. Цель заключается в том, чтобы найти «наилучший» путь от корня к листу при выполнении определенных условий. Эти условия и значение понятия «наилучший» для пути зависит от задачи.
Деревья решений обычно имеют громадный размер. Дерево решений для игры в крестики‑нолики содержит более полумиллиона узлов. Эта игра довольно проста, и многие реальные задачи намного более сложны. Соответствующие им деревья решений могли бы содержать больше узлов, чем число атомов во вселенной.
В этой главе обсуждаются методы, которые можно использовать для поиска в таких огромных деревьях. Во‑первых, в ней вначале рассматриваются деревья игры (game trees). На примере игры в крестики‑нолики обсуждаются способы поиска в деревьях игры для нахождения наилучшего возможного хода.
В следующих разделах описываются способы поиска в более общих деревьях решений. Для самых маленьких деревьев, можно использовать метод полного перебора (exhaustive searching) всех возможных решений. Для деревьев большего размера, можно использовать метод ветвей и границ (branch‑and‑bound technique) позволяет найти наилучшее решение без необходимости выполнять поиск по всему дереву.
Для очень больших деревьев нужно использовать эвристический метод или эвристику (heuristic). При этом полученное решение может быть не наилучшим из возможных решений, но оно, тем не менее, лежит достаточно близко к наилучшему, чтобы его можно было использовать. Используя эвристики, можно проводить поиск практически в любых деревьях решений.
В конце этой главы обсуждаются некоторые очень сложные задачи, которые вы можете попытаться решить при помощи метода ветвей и границ или эвристического метода. Многие из этих задач имеют важные применения, и нахождение хороших решений для них крайне необходимо.
Поиск в деревьях игры
Стратегию настольных игр, таких как шахматы, шашки, или крестики‑нолики можно смоделировать при помощи деревьев игры. Если в какой то момент игры существует 30 возможных ходов, то соответствующий узел в дереве игры будет иметь 30 ветвей.
========187
Например, для игры в крестики‑нолики корневой узел соответствует начальной позиции, при которой доска пуста. Первый игрок может поместить крестик в любую из девяти клеток доски. Каждому из этих девяти возможных ходов соответствует выходящая из корня ветвь. Девять узлов на конце эти ветвей соответствуют девяти различным позициям после первого хода игрока.
После того, как первый игрок сделал ход, второй может поставить нолик в любую из оставшихся восьми клеток. Каждому из этих ходов соответствует ветвь, выходящая из узла, соответствующего текущей позиции игры. На рис. 8.1 показан небольшой фрагмент дерева игры в крестики‑нолики.
Как можно увидеть на рис. 8.1, дерево игры в крестики‑нолики растет очень быстро. Если оно продолжит расти таким образом, так что каждый следующий узел в дереве будет иметь на одну ветвь меньше, чем его родитель, то дерево целиком будет иметь 9 * 8 * 7 … * 1 = 362.880 листьев. В дереве будет 362.880 возможных путей, соответствующих 362.800 возможным играм.
В действительности многие из узлов дерева будут отсутствовать, так как соответствующие им ходы запрещены правилами игры. Если игрок, ходивший первым, за три своих хода поставит крестики в верхней левой, верхней средней и верхней правой клетках, то он выиграет и игра закончится. Узел, соответствующий этой позиции, не будет иметь потомков, так как игра завершается на этом шаге. Эта игра показана на рис. 8.2.
После удаления всех невозможных узлов в дереве остается около четверти миллиона листьев. Это все еще очень большое дерево, и поиск его методом полного перебора занимает достаточно много времени. Для более сложных игр, таких как шашки, шахматы или го, деревья игры имеют огромный размер. Если бы во время каждого хода в шахматах игрок имел 16 возможных вариантов, то дерево игры имело бы более триллиона узлов после пяти ходов каждого из игроков. В конце этой главы обсуждается поиск в таких огромных деревьях игры, а следующий раздел посвящен более простому примеру игры в крестики‑нолики.
@Рис. 8.1. Фрагмент дерева игры в крестики‑нолики
========188
@Рис. 8.2. Быстрое окончание игры