Основные понятия Цель настоящей лекции является объяснение важности анализа алгоритмов, их обозначения, отношения и решение как можно большего количества задач. Давайте сначала сосредоточимся на понимание основных элементов алгоритмов, важности анализа алгоритмов. После завершения этой лекции вы должен уметь определять сложность любого заданного алгоритма (особенно рекурсивных функций). Итак рассмотрим понятия с которыми работает алгоритм Переменные Переменные это хранилище в котором хранится данные, в процессе работы алгоритма в переменных могут хранится различные данные, таким образом переменные в алгоритмах нужны для хранения данных. Типы данных В переменных могут храниться любые значения например целые числа (10,20), действительные числа (0,23, 5,5) или просто 0 и 1. Чтобы использовать переменные, нам нужно связать их с типом значений, которые они могут принимать, а тип данных - это имя, используемое в программирование для обозначения набора данных с предопределенными значениями. Примеры типов данных: целое число, действительное число с плавающей запятой, номер единицы, символ, строка и т. д. Компьютерная память заполнена нулями и единицами. Если у нас есть данные , и мы хотим ее закодировать, то очень сложно дать решение в виде нулей и единиц. Чтобы помочь пользователям, языки программирования и компиляторы предоставляют нам типы данных. Например, целое число integer занимает 2 байта (на самом деле значение зависит от компилятора), float занимает 4 байта и т. д. Это говорит о том, что в памяти мы объединяем 2 байта (16 бит) и называя это целым числом. Точно так же объединяя 4 байта (32 бита) и называя его вещественным числом. Тип данных снижает трудозатраты на кодирование. На верхнем уровне есть два типа данных: • Системные типы данных (также называемые примитивными типами данных) • Типы данных, определяемые пользователем Системные типы данных (примитивные типы данных) Типы данных, которые определены системой, называются примитивными или базовыми типами данных. Примитивные типами данных во многих языках программирования являются следующие типы: int, float, char, double, bool и т. д. Количество байт, выделенных для каждого примитивного типа данных, зависит от языков программирования, компилятора и операционной системы. Для одного и того же примитивного типа данных разные языки могут использовать разные размеры. В зависимости от размера типов данных общие доступные значения также будут разными. Например, «int» может занимать 2 или 4 байта. Если он занимает 2 байта (16 бит), то общий возможный значения от -32 768 до +32 767 (от -215 до 215-1). Если требуется 4 байта (32 бита), то возможные значения от -2 147 483 648 до +2 147 483 647 (от -231 до 231-1). То же самое в случаях с другими типами данных. Типы данных, определяемые пользователем Если системных типов данных недостаточно, то большинство языков программирования позволяют определять новые типы данных, называемых типами данных, определяемыми пользователем. Хорошим примером пользовательских типов данных является структуры в C / C ++ и классы в Java. Например, в приведенном ниже фрагменте объединяются несколько системных типов данных и создается определяемый пользователем тип данных по имени "Новый тип". Это дает больше гибкости и комфорта при работе с памятью компьютера. Структуры данных Основываясь на приведенном выше рассуждении, когда у нас есть данные в переменных, нам нужен какой-то механизм для манипулирование этими данными для решения задачи. Структура данных - это особый способ хранения и организация данных на компьютере, чтобы их можно было эффективно использовать. Структура данных - это особый формат для организации и хранения данных. Общие типы структур данных включают массивы, файлы, связанные списки, стеки, очереди, деревья, графы и так далее. В зависимости от организации элементов структуры данных подразделяются на два типа: 1) Линейные структуры данных: доступ к элементам осуществляется в последовательном порядке, но не обязательно хранить все элементы последовательно. Примеры: связанные списки, стеки и очереди. 2) Нелинейные структуры данных: элементы этой структуры данных хранятся доступны в нелинейном порядке. Примеры: деревья и графы. Абстрактные типы данных (ADT) Прежде чем определять абстрактные типы данных, давайте рассмотрим другой взгляд на определенные системой.типы данных. Все мы знаем, что по умолчанию все примитивные типы данных (int, float и т. д.) поддерживают базовые операции, такие как сложение и вычитание. В системе предусмотрены реализации этих операций для примитивные типы данных, причем для разных типов они реализованы различными группами машинных команд. Для определяемых пользователем типов данных, нам также необходимо определить операции, эти операции может быть даже над всей структурой . Реализация этих операций может быть осуществлена, когда мы действительно хотим их использовать. Это значит, обычно типы данных, определяемые пользователем, определяются вместе с их операциями. Чтобы упростить процесс решения задачи, мы объединяем структуры данных с операциями над ними. Такое объединение мы называем абстрактными типами данных (AТД). AТД состоит из двух частей: 1. Объявление данных 2. Определение операций Обычно используемые АТД включают: связанные списки, стеки, очереди, очереди c приоритами, двоичные деревья, словари, множества (объединение и поиск), хеш-таблицы, графы и многие другие структуры данных. Например, стек при хранении данных использует механизм LIFO (Last-InFirst-Out) . Последний элемент, вставленный в стек, - это первый элемент, который удаляется из него. Общие операции являются : создание стека, размещение элемента в стеке, извлечение элемента из стека, поиск текущей вершины стека, определение количества элементов в стеке и т. д. При определении АТД не беспокоятся о деталях реализации. Они включаются в реализацию только тогда, когда мы хотим их использовать. Различные типы АТД подходят для разных типов приложений, а некоторые узкоспециализированы для решения конкретных задач. Что такое алгоритм? Термин «Алгоритм» происходит от имени хорезмского учѐного АльХорезми Мухаммед бен-Муса (825 г н.э.). В явном виде понятие алгоритма сформировалось в начале XX века благодаря работам таких учѐных, как Д. Гильберт, К. Гѐдель, С. Клини, А.Чѐрч, Э. Пост, А. Тьюринг, Н. Винер, А.А. Марков. Вот некоторые определения алгоритма: «Алгоритм – это конечный набор правил, который определяет последовательность операций для решения конкретного множества задач и обладает пятью важными чертами: конечность, определѐнность, ввод, вывод, эффективность» (Д. Э. Кнут). «Алгоритм – это всякая система вычислений, выполняемых по строго определѐнным правилам, которая после какого-либо числа шагов заведомо приводит к решению поставленной задачи» (А.Колмогоров). «Алгоритм – это точное предписание, определяющее вычислительный процесс, идущий от варьируемых исходных данных к искомому результату» (А. Марков). «Алгоритм — точное предписание о выполнении в определѐнном порядке некоторой системы операций, ведущих к решению всех задач данного типа» (Философский словарь под ред. М. М.Розенталя). Определение 1. Алгоритм – это заданное на некотором языке конечное предписание, задающее конечную последовательность выполнимых элементарных операций для решения задачи, общее для класса возможных исходных данных. Пусть D – область (множество) исходных данных задачи, а R – множество возможных результатов, тогда алгоритм осуществляет отображение DR → Это отображение может быть не полным. Алгоритм называется частичным алгоритмом, если получен результат только для некоторых dD и полным алгоритмом, если алгоритм получает правильный результат для всех d∈ D Определение 2. Алгоритм – точный набор инструкций, описывающих порядок действий исполнителя для достижения результата решения задачи за конечное время. Различные определения алгоритма в явной или неявной форме влекут за собой ряд требований: алгоритм должен содержать конечное количество элементарно выполнимых предписаний, т.е. удовлетворять требованию конечности записи; алгоритм должен выполнять конечное количество шагов при решении задачи, т.е. удовлетворять требованию конечности действий; алгоритм должен быть единым для всех допустимых исходных данных, т.е. удовлетворять требованию универсальности; алгоритм должен приводить к правильному по отношению к поставленной задаче решению, т.е. удовлетворять требованию правильности Формальные свойства алгоритмов Дискретность— алгоритм должен представлять процесс решения задачи как последовательное выполнение некоторых простых шагов. Для выполнения каждого шага алгоритма требуется конечный отрезок времени, то есть преобразование исходных данных в результат осуществляется во времени дискретно. Детерминированность — определѐнность. В каждый момент времени следующий шаг работы однозначно определяется состоянием системы. Таким образом, алгоритм выдаѐт один и тот же результат (ответ) для одних и тех же исходных данных. Понятность — алгоритм для исполнителя должен включать только те команды, которые ему (исполнителю) доступны, которые входят в его систему команд. Завершаемость(конечность) — при корректно заданных исходных данных алгоритм должен завершать работу и выдавать результат за конечное число шагов. Массовость — универсальность. Алгоритм должен быть применим к разным наборам исходных данных. Алгоритм содержит ошибки, если приводит к получению неправильных результатов либо не даѐт результатов вовсе. Алгоритм не содержит ошибок, если он даѐт правильные результаты для любых допустимых исходных данных. В традиционном изучении алгоритмов есть два основных критерия оценки достоинств алгоритма: корректность (дает ли алгоритм решение задачи за конечное число шагов?) эффективность (сколько ресурсов (с точки зрения памяти и времени) требуется для выполнения задачи.