- •Введение
- •Основные понятия и определения
- •Типы данных
- •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. Пример решения задачи поиска с использованием хеш-таблицы
2.3.4. Очереди с приоритетами
В реальных задачах часто возникает необходимость организации очередей, принцип работы которых отличен от FIFO. Порядок выборки элементов в них определяется приоритетами элементов. Приоритет — это некоторое числовое значение, связанное с элементами очереди, в простейшем случае, это может быть само значение элемента. При выборке элемента из очереди каждый раз выбирается элемент с наибольшим приоритетом.
Различают два способа реализации очередей с приоритетами.
1. Очереди с приоритетным включением. В этом случае очередь всё время поддерживается упорядоченной, т.е. каждый новый элемент помещается в то место очереди, которое определяется его приоритетом.
2. Очереди с приоритетным исключением. Новые элементы помещаются в конец очереди, при исключении элемента ищется элемент с максимальным приоритетом.
Реализация очередей с приоритетами на базе отсортированных массивов или списков используется при небольшом количестве элементов такой очереди. При небольшом количестве приоритетов может использоваться так называемый корзинный способ. Наиболее удобной формой реализации больших очередей с приоритетами является реализация с помощью частично упорядоченных деревьев. Но об этом речь пойдет в следующих разделах.
2.3.5. Пример программы с использованием очереди
Лабиринт представляет собой клетчатое поле NxM клеток, некоторые из них пустые, другие закрашены - через них проходить нельзя. За один шаг можно перейти из текущей клетки в одну из свободных соседних. Требуется найти длину кратчайший путь из левого верхнего угла в правый нижний. Лабиринт считывается из текстового файла input.txt, где в первой строке записаны числа N и M (через пробел), а в каждой из последующих N строк находятся M символов информации о клетках лабиринта. При этом символ пробела обозначает пустую клетку, символ 'x' - закрашенную. Результат работы программы выводится на экран.
Идея решения состоит в следующем («метод волны»). Для начала модифицируем созданный ранее класс очереди. Пусть элементы очереди представляют собой структуру из трёх полей - координаты клетки и число шагов до неё от левого верхнего угла:
struct cell
{ int x,y,l;
};
typedef cell type_of_data;
После чтения информации о лабиринте создаем очередь и помещаем в нее первый элемент с координатами левого верхнего угла и числом шагов 0.
Алгоритм «метода волны» состоит в следующем. На каждом шаге извлекаем очередной элемент, смотрим, в какие соседние клетки можно переместиться из текущей, и помещаем в очередь элементы, соответствующие этим клеткам. При этом для них делаем количество шагов на единицу больше, чем для извлечённого элемента. После этого необходимо пометить текущую клетку как закрашенную, чтобы не возвращаться в нее в дальнейшем, и перейти к извлечению нового элемента из очереди.
В конце концов либо окажется, что очередь пуста (это означает, что все возможные пути пройдены, и все свободные клетки помечены), либо очередной из извлеченных элементов окажется с координатами правого нижнего угла. В последнем случае количество шагов в структуре и будет решением задачи, т.е. длиной кратчайшего пути. Это объясняется тем, что элементы в очередь помещаются по возрастанию количества шагов.
#include <fstream.h>
#include "queue.cpp"
main() {
ifstream fi("input.txt");
int N,M;
fi>>N>>M; fi.get(); //Считывание размеров лабиринта
char s[100]; int a[10][10], i, j;
for (i=0; i<N; i++) { //Чтение информации о клетках
fi.getline(s,100);
for (j=0; j<M; j++) {
if (s[j]=='.') a[i][j]=0;
else a[i][j]=1;
}
}
queue q; // Очередь абсцисс, ординат и длин путей
cell c;
// Заносим в очередь первую клетку:
c.x=0; c.y=0; c.l=0; q.enqueue(c);
int len;
while (!q.isnull())
{ c=q.dequeue();
i=c.y; j=c.x; len=c.l;
if ((i==N-1)&&(j==M-1)) break; // Путь найден
// Проверяем соседние с (i,j) клетки:
c.l++; //увеличиваем путь на 1
if ((i>0)&&(!a[i-1][j])) { c.y--; q.enqueue(c); c.y++; }
if ((i<N-1)&&(!a[i+1][j])) { c.y++; q.enqueue(c); c.y--; }
if ((j>0)&&(!a[i][j-1])) { c.x--; q.enqueue(c); c.x++; }
if ((j<M-1)&&(!a[i][j+1])) { c.x++; q.enqueue(c); c.x--; }
a[i][j]=1;
}
if ((i==N-1)&&(j==M-1)) cout<<"Длина кратчайшего пути равна "<<len;
else {
q.makenull();
cout<<"Путь в лабиринте не найден.";
}
cin.get(); return 0;
}
Стеки и очереди являются частными случаями более универсальной структуры данных— линейных списков.