
- •Программирование и алгоритмические языки. Курс за второй семестр. Абстрактные типы данных.
- •Задача раскраски.
- •Перечисление последовательностей фиксированной длины.
- •Два взгляда на диаграммы – графы и автоматы.
- •А нглия
- •Деревья
- •Словарный порядок на последовательностях произвольной длины
- •Статическая реализация стеков.
- •Очереди. Статическая реализация.
- •Статическая реализация деревьев.
- •Автоматы как структуры данных
- •Статическая реализация графов. Проблема фрагментации памяти. Списочные структуры.
- •Общая схема реализации автомата как списка.
- •Обработка кучи.
- •Динамическая реализация абстрактных типов ссылками. Ссылочные типы Паскаля.
- •Ссылочные типы Паскаля. Синтаксис типов.
- •Объявление списочной структуры в Паскале.
- •Реализация стеков.
- •Реализация очередей.
- •Основные операции над стеками.
- •Обработка деревьев. Деревья выражений.
- •Поиск атома.
- •Различные объединения типов. Записи типов с вариантами.
- •Создание дерева. Перевод из префиксной записи. Представление записи.
- •Анализ алгоритма вычисления. Дерево как последовательность ветвей.
- •Задача синтаксического анализа.
- •Графы-выражения.
- •Раздельное описание абстрактных типов. Модульное программирование.
- •Проблема с кратным использованием модулей.
- •Деревья как структуры данных.
- •Деревья поиска.
- •Включение в дерево поиска.
- •Другие обходы дерева. Обход в ширину.
- •Рекурсивные процедуры и функции. Примеры применения.
- •Поиск в дереве.
- •Проблемы с семантикой рекурсии.
- •Введение в машинно-ориентированное (ссылочное) программирование.
- •Создание новых структурных операторов.
- •Формальная семантика goto и неструктурных программ.
- •Мини-Паскаль.
- •Представление сложных типов. Адресная арифметика.
- •Проблемы реализации ввода-вывода. Идея буферизации.
- •Реализация процедур read и write.
- •Реализация структур управления.
- •Путь наверх. Реализация процедур-подпрограмм.
- •Передача параметров.
- •Сохранение и восстановление значений. Соглашение о связях.
- •Введение в теоретическое программирование. Границы программирования. Принципиальная и практическая неразрешимость.
- •О формальной спецификации. Мир задачи как автомат.
- •Процедуры как функции на множестве состояний. Процедуры как преобразователи предикатов.
- •Универсальные методы решения задач.
Программирование и алгоритмические языки. Курс за второй семестр. Абстрактные типы данных.
Приближённые к реальности, но отсутствующие в данном языке программирования типы данных, называются абстрактными.
«Программы = алгоритмы (процедуры) + структуры данных»
Н. Вирт
Идею нисходящего проектирования – многошаговый процесс создания (или выбора существующих) специализированных математических языков описания задач (подзадач) – мы ранее применяли к структурам управления. Применение к структурам данных – этот процесс был, как правило, одношаговый. При решении действительно сложных задач процесс нисходящего проектирования продолжается и на выбор промежуточных структур данных, то есть в целом на создание промежуточных абстрактных типов.
Тип
Задача раскраски.
Выяснить, можно ли данную карту правильно раскрасить данным количеством цветов. Если да, то предъявить все возможные раскраски. Раскраска правильная, если никакие две соседние страны не окрашены в один цвет.
Делаем первые выводы относительно определения типа данных.
Type tСтраны = 1..n; {Можно взять произвольный порядковый тип}
tКарта = array [tСтраны,tСтраны] of Boolean; {На этом типе обязана быть определена единственная функция}
var карта: tКарта;
m:cardinal;
Можно: boolean;
Раскраска: tРаскраска; {Определение типа откладываем до определения операций, которые нужны в алгоритме}
Function Правильная (раскраска: tРаскраска):boolean;
{правильная:=i,jtСтраны (соседи (i,j)(i<j) раскраска(i) раскраска j)}
{Стрелка – логическая связь – «если, то»}
{правильная:= }
Begin
Result:=true;
i:=первая страна;
while (i<=последняя страна) and (Result) do
begin
j:=succ(i);
while (j<=последняя страна) and Result do
begin
if соседи (i,j) then if раскраска (i) = раскраска (j) then Result:=false;
else j:=succ(j);
end;
i:=succ(i);
end;
Begin
{Можно:= раскраска – tРаскраска - правильная}
можно:=false;
раскраска:=первая раскраска;
while not (конечная раскраска) do
Begin
If (правильная раскраска) then
Begin
Можно:=true;
Write (Правильная раскраска);
End;
Раскраска:=следующая раскраска;
End;
End.
Мы отождествляем тип tКарта с функцией “Соседи”, задавая её в виде булевского массива. Не забудь переименовать в алгоритме Соседи на Карта!
tРаскраска: tСтранаtЦвет
array[tСтрана] of tЦвет
Однако основной алгоритм требует, чтобы тип tРаскраска был порядковым. Нам необходима возможность перечислять раскраску.
Перечисление последовательностей фиксированной длины.
n циклов дали бы нужный порядок, но мы не можем выразить такой оператор синтаксически, однако это даёт идею того, в каком порядке можно перебирать последовательности (конечные функции) – в словарном (лексикографическом).
a=a1,…,an
b=b1,…,bn
a<b ai0<bi0, где i0 – наименьший символ i такой, что aibi и i<i0 ai=bi
Procedure Следующая ({var Раскраска: tРаскраска;var Кончились:boolean});
{Выдаёт раскраску, следующую за данной, кладёт «Кончились» в true, если таковой нет}
Begin
Кончились:=false;
i:=последняя страна;
c:=раскраска[i];
while not Кончились and (раскраска[i]последний цвет) do
Begin
Раскраска[i]:=первый цвет;
i:=i-1;
кончились:=i=0;
if not Кончились then раскраска[i]:=succ(раскраска[i]);
end;
{Поддерживается быстрое вычисление конъюнкции}
Упражнение. Завершить первый вариант решения задачи.
Привлекательное своей простотой наше решение грешит единственным недостатком – оно неэффективно. Непосредственный выбор структуры данных под алгоритм игнорирует вопросы компактного хранения. Но основная сложность – эффективность по времени. Полный перебор раскрасок даёт (число цветов – число стран) – экспоненциальный алгоритм. Потратится много времени. Такие алгоритмы в программировании считаются практически невыполнимыми за реальное время.
Вопрос: нужно ли было писать такой алгоритм???
Ответ: несомненно, ДА!!!
Правильные программы имеет смысл улучшать. Преобразовывать программы эквивалентно проще, чем писать новые, но основной туш таков: достоинство плохих решений – простые решения универсальны и служат исходной точкой для решения очень широкого круга задач. Теория даёт простые решения.