
- •Дискретная математика
- •6.050102 “Компьютерная инженерия” содержание
- •1 Теория множеств 7
- •2 Математическая логика 15
- •3 Формальные теории 35
- •4 Теория графов 47
- •5 Элементы теории чисел 80
- •6 Теория алгоритмов 121
- •Введение
- •1 Теория множеств
- •1.1 Множества и подмножества
- •1.1.1 Элементы множества
- •1.2 Аксиомы теории множеств
- •1.3 Способы задания множеств
- •1.4 Операции над множествами
- •1.5 Элементы алгебры множеств
- •1.5.1 Определение алгебры множеств
- •1.5.2 Основные законы алгебры множеств
- •1.5.3 Принцип двойственности
- •2 Математическая логика
- •2.1 Функции алгебры логики (булевые функции)
- •2.1.1 Способы задания булевых функций
- •2.1.2 Логические функции одной переменной
- •2.1.3 Логические функции двух переменных
- •2.2.6 Функционально полные системы булевых функций
- •2.3 Алгебра буля
- •2.3.1 Определение алгебры. Теорема Стоуна
- •2.3.2 Законы алгебры логики
- •2.3.3 Разложения функций по переменным
- •2.3.4 Приведение логических функций
- •2.3.5 Импликанты и имплициенты булевых функций
- •2.3.6 Методы минимизации логических функций
- •2.4 Алгебра жегалкина
- •2.4.1 Преобразование функций в алгебре Жегалкина
- •2.4.2 Переход от булевой алгебры к алгебре Жегалкина
- •3 Формальные теории
- •3.1 Основные принципы построения формальных теорий исчисления
- •3.2 Определение исчисления высказываний
- •3.2.1 Метатеоремы исчисления высказываний
- •3.2.2 Схемы исчисления высказываний
- •3.3 Исчисление предикатов
- •3.3.1 Определение формальной теории pl
- •3.3.2 Принцип резолюции в исчислении предикатов
- •3.3.3 Схемы доказательств в исчислении предикатов
- •4 Теория графов
- •4.1 История теории графов
- •4.2 Основные определения
- •4.3 Способы представления графов
- •4.3.1 Матрицей смежности
- •4.3.2 Матрицей инцидентности
- •4.4 Пути в графах
- •4.4.1 Задача о кратчайшем пути
- •4.4.2 Алгоритм Дейкстры нахождения кратчайшего пути в графе
- •4.5 Транспортные сети
- •4.5.1 Потоки в транспортных сетях
- •4.5.2 Задача нахождения наибольшего потока в транспортной сети
- •4.5.3 Алгоритм Форда и Фалкерсона нахождения максимального потока транспортной сети
- •4.5.4 Транспортная задача
- •4.6 Обходы в графах
- •4.6.1 Эйлеровы графы
- •4.6.2 Алгоритм Флёри нахождения эйлерова цикла
- •4. Если получился цикл, но не ейлеров, то отбрасываем данную последнюю вершину и повторяем пункт 2.
- •4.6.3 Гамильтоновы циклы
- •4.6.4 Метод ветвей и границ.
- •4.6.5 Метод ветвей и границ в задаче о коммивояжёре
- •4.7 Деревья
- •4.7.1 Построение экономического дерева
- •4.7.2 Алгоритм Краскала
- •5 Элементы теории чисел
- •5.1 Модулярная арифметика
- •5.1.1 Алгоритм Евклида для нахождения наибольшего общего делителя
- •5.1.2 Вычисление обратных величин
- •5.1.3 Основные способы нахождения обратных величин
- •5.1.4 Китайская теорема об остатках
- •5.2 Кодирование
- •5.2.1 Оптимальное кодирование
- •5.3 Обнаружение и исправление ошибок
- •5.3.1 Общие понятия
- •5.3.2 Линейные групповые коды
- •5.3.2 Код Хэмминга
- •5.3.3 Циклические коды
- •5.3.4 Построение и декодирование конкретных циклических кодов
- •5.4 Сжатие информации
- •5.4.1 Исключение повторения строк в последующих строках
- •5.4.2 Алгоритм lzw
- •6 Теория алгоритмов
- •6.1. Основные понятия
- •6.1.1 Основные требования к алгоритмам
- •6.1.2 Блок–схемы алгоритмов
- •6.1.3 Представление данных
- •6.1.4 Виды алгоритмов
- •6.1.5 Правильность программ
- •6.1.6 Эффективность алгоритмов
- •6.1.7 Сходимость, сложность, надежность
- •6.2 Универсальные алгоритмы
- •6.2.1 Основные понятия
- •6.2.2 Машины Тьюринга
- •6.2.3 Рекурсивные функции
- •6.2.5 Тезис Черча-Тьюринга
- •6.2.6 Проблема самоприменимости
- •6.3 Языки и грамматики
- •6.3.1 Общие понятия
- •6.3.2 Формальные грамматики
- •6.3.3 Иерархия языков
- •6.4 Параллельные вычисления
- •Рекомендованная литература
6.1.2 Блок–схемы алгоритмов
Связи между шагами можно изобразить в виде графа:
Такой граф, в котором вершинам соответствуют шаги, а ребрам – переходы между шагами, называется блок-схемой алгоритма. Его вершины могут быть двух видов:
1) из которой выходит одно ребро – операторы;
2) из которой выходит два ребра – логические условия или предикаты.
Кроме того, имеется единственный оператор конца (из которого не выходит ни одного ребра) и единственный оператор начала. Важной особенностью блок-схем является то, что связи которые она описывает, не зависят от того, являются ли шаги элементарными или представляют собой самостоятельные алгоритмы – блоки. Для данного блока неважно, как устроены другие блоки; для программирования блока достаточно знать, где лежит исходная информация, какова форма её предcтавления, что должен делать блок и куда записывать результат. Блок-схемы соответствуют логике, которой пользуется программист для создания сложных, многовариантных, итеративных планов действий.
При всей наглядности языка блок-схем не следует переоценивать его возможности. Он отражает связи лишь по управлению. Блок-схемы не содержат сведений ни о данных, ни о памяти, ни о используемом наборе элементарных шагов. В частности, если в блок-схемах нет циклов, это еще не значит, что циклов нет в алгоритме. По существу, блок-схема это не язык, а средство для описания детерминизма.
6.1.3 Представление данных
При разработке программ стоит задача представления, моделирования и использования самых разных видов информации.
Информацией называют абстрактное содержание какого-либо высказывания, описания, указания, сообщения или известия. Внешнюю форму информации называют представлением. Представление интерпретируется, чтобы получить информацию. Информация в ее абстрактном виде не может быть записана непосредственно, а только может быть как-то изображена.
Понятие числа в математике – абстракция, которая понимается независимо от конкретного изображения. Законы в математике справедливы для чисел в римской записи, так же как и при двоичной или десятичной записи. Различные способы представления чисел существенно различаются с точки зрения удобства их использования для определенных процессов обработки. Алгоритмы работают над элементами данных, которые могут быть объединены в так называемый носитель (множества данных). При разработке программ используется понятие типа данных. Интуитивно ясно, что тип данных характеризует некоторую группу однородных данных. В зависимости от того, является ли данное неделимым или его возможно разложить на компоненты, различают простые и структурные данные. К общеизвестным простым данным относятся литеры,целые и вещественные числа, булевские значения "ложь" и "истина". Примерами структурных данных служат массивы, записи, файлы и т.д.
Несмотря на долгую историю типов данных, до сих пор не утвердилась единая концепция типообразования. К традиционным простым и структурным типам в настоящее время добавляются средства конструирования абстрактных, инкапсулированных, родовых и прочих типов данных. К сожалению, каждое из таких средств существует само по себе. Это не позволяет рассматривать каждый тип данных как результат действия некоторого единого механизма и связать все типы данных программ или языка программирования в стройную систему.
По отношению к типам данных можно выделить конкретный и абстрактный аспекты их рассмотрения. Тип данных, предоставляемый конкретной системой программирования – конкретен, для каждого из них транслятор обеспечивает конкретный способ представления значений (в виде последовательности битов памяти) и конкретные алгоритмы реализации операций. В то же время типы данных, предлагаемые языком программирования, абстрактны. Для каждого из них описание языка задает только имена основ, имена и типы операций и смысл операций. В разных трансляторах одному и тому же абстрактному типу сопоставляются различные конкретные типы.
В описании языков программирования типы данных можно разделить на два класса: стандартные и произвольные. Стандартные типы характеризуют язык программирования, их спецификация осуществляется разработчиками языка. Произвольные типы характеризуют конкретную программу, их спецификацию и реализацию осуществляют пользователи. Как стандартные, так и произвольные типы можно разделить на конкретные и родовые типы. Конкретный тип характеризует определенное множество значений, он не требует дальнейшего уточнения и готов к непосредственному употреблению. Родовой тип характеризует множество множеств значений и требует конкретизации путем представления аргументов, переменная такого типа не может быть полностью обработана до завершения конкретизации типа. Примеры конкретных типов: целый, литерный, отрезок от 1 до 10, массив из 100 целых, стек из 100 вещественных, родовых типов: отрезок, стек, запись, массив.
В вычислительной машине программы обычно оперируют с таблицами информации. В большинстве случаев это не просто аморфные массы числовых величин: в таблицах присутствуют важные структурные отношения между элементами данных. В простейшем случае таблица может быть линейным списком, в более сложных ситуациях таблица может быть двумерным или n-мерным массивом (при весьма большом n), она может иметь структуру дерева, представляющего отношения иерархии или ветвления, или это может быть сложная многосвязная структура с огромным множеством взаимных соединений (как в человеческом мозгу).
Выбор структур данных может существенно повлиять на скорость и эффективность реализованного алгоритма.
Рассмотрим преимущества и недостатки использования массивов. Среди преимуществ следующие:
массивы помогают объединять множества данных в осмысленные группы;
имена массивов с индексами минимизируют потребность в слежении за многими элементами данных с различными именами;
использование индексов обеспечивает непосредственный и автоматический доступ к любому элементу в массиве;
индексация позволяет производить с помощью циклов авто-матическую, быструю и эффективную обработку всех данных или выделенных подмножеств, как то: инициализация, поиск, хранение и модификация.
Недостатки массивов не так очевидны. Лучше всего массивы годятся для данных, значения которых не изменяются и порядок которых также не изменяется.
Связанный список представляет собой структуру данных, которая требует дополнительной памяти, но позволяет легко вносить изменения. Линейный связанный список – это конечный набор пар, каждая из которых состоит из информационной части и указующей части. Каждая пара называется ячейкой. Линейные связанные списки – это эффективная структура данных для моделирования ситуаций, в которых подвергаются изменениям упорядоченные массивы элементов данных. Это справедливо для случаев, когда модификациями являются главным образом внесение элементов в середину массивов или удаление элементов из середины массива.
Когда изменения касаются лишь начала и конца, необходимость в связанных списках исчезает. В таких случаях используют стек, который представляет собой бесконечную в одну сторону последовательность слов памяти. Для запоминания элемента данных в стеке элемент заносят в верхнее слово, сдвигая тем самым вниз все другие слова, хранящиеся в стеке. Выбор элементов из стека возможен лишь считыванием по одному из вершины, все остальные элементы при этом сдвигаются вверх. Мы не имеем права выбирать элементы данных внутри стека.
В очереди элементы добавляются с одного конца, а выбираются с другого. Для моделирования очереди, как правило, используют линейный массив и две целые переменные, которые указывают на первый и последний элемент очереди.
Деревья – наиболее важные нелинейные структуры, встречающиеся в вычислительных алгоритмах. Всякая иерархическая классификационная схема принимает в конце концов вид дерева. Наиболее важный тип деревьев – бинарные или двоичные. Двоичное дерево обычно определяют как конечное множество узлов, которое либо пусто, либо состоит из корня и двух двоичных деревьев. Многие деревья, возникающие в прикладных задачах, по существу являются бинарными. Кроме того, любое дерево можно представить в виде двоичного.
Для работы с древовидными структурами имеется множество алгоритмов, во всех встречается одна и та же идея: прохождение дерева – это способ методичного исследования узлов дерева, при котором каждый узел проходится только один раз.