
- •1 Основные принципы перегрузки операций
- •Запреты на перегрузку операций
- •3 Структуры
- •Доступ к элементам структур
- •Динамическое распределение памяти
- •Связанные списки
- •Очереди
- •7. Программные продукты и их основные характеристики: основные понятия программного обеспечения; характеристики программных продуктов; защита программных продуктов; классификация программных продуктов
- •4. Классы программных продуктов
- •1) Составление технического задания на программирование
- •2) Составление технического проекта
- •3) Создание рабочей документации (рабочего проекта)
- •4) Ввод в действие
- •1) Диалоговый режим
- •2) Графический интерфейс пользователя
- •9. Сети эвм и протоколы передачи информации:
- •10. Экспертные системы: архитектура, типы решаемых задач, методика построения, области применения. Различные подходы к построению систем ии.
- •11. Понятие модели данных. Иерархическая, сетевая, реляционная, объектная модель. Типы структур данных. Операции над данными. Ограничения целостности.
- •2.3. Иерархическая модель данных (имд)
- •12. Нормализация отношений. Нормальные формы. Запросы и операторы манипулирования данными. Язык запросов sql.
Очереди
Другой распространенной структурой данных является очередь В очереди узлы удаляются только с головы, а добавляются только в хвост очереди. По этой причине очереди часто называют структурами данных типа первым пришел - первым ушел (FIFO). Операции постановки в очередь и удаления из очереди носят названия enqueue (поставить в очередь) и dequeue (исключить из очереди).
Большинство компьютеров оборудовано только одним процессором, поэтому в каждый конкретный момент времени может обслуживаться только один пользователь (задача). Остальные же пользователи ставятся в очередь. Каждый стоящий в очереди постепенно перемещается к ее началу по мере обслуживания впереди стоящих пользователей.
Очереди также используются при организации буфера печати.
4.Нестрогое понятие алгоритма. Свойства алгоритмов. Уточнение понятия алгоритма. Алгоритм как абстрактная машина: алгоритмическая машина Поста, Тьюринга, тезис Тьюринга и его обоснование. Нормальные алгоритмы Маркова. Сопоставление алгоритмических моделей. Проблема алгоритмической разрешимости.
Можно сказать, что алгоритм - это точно определенная (однозначная) последовательность простых (элементарных) действий, обеспечивающих решение любой задачи из некоторого класса.
Однако данное утверждение нельзя принять в качестве строгого определения алгоритма, поскольку в нем использованы другие неопределяемые понятия -однозначность, элементарность и др.
Понятие можно уточнить, указав перечень общих свойств, которые характерны для алгоритмов. К ним относятся:
Дискретность алгоритма означает, что алгоритм разделен на отдельные шаги (действия), причем, выполнение очередного шага возможно только после завершения всех операций на предыдущем шаге. При этом набор промежуточных данных конечен и он получается по определенным правилам из данных предыдущего шага.
Детерминированность алгоритма состоит в том. Что совокупность промежуточных величин на любом шаге однозначно определяется системой величин, имевшихся на предыдущем шаге. Данное свойство означает, что результат выполнения алгоритма не зависит от того, кто (или что) его выполняет (т.е. от исполнителя алгоритма), а определяется только входными данными и шагами (последовательностью действий) самого алгоритма.
Элементарность шагов: закон получения последующей системы величин из предыдущей должен быть простым и локальным. Какой шаг можно считать элементарным, определяется особенностями исполнителя алгоритма.
Направленность алгоритма: если способ получения последующих величин из каких-либо исходных не приводит к результату, то должно быть указано, что следует считать результатом алгоритма.
Массовость алгоритма: начальная система величин может выбираться из некоторого множества.
Последнее свойство алгоритма означает, что один алгоритм, т.е. одна и та же последовательность действий, в общем случае, может применяться для решения некоторого класса (т.е. многих) задач. Для практики и, в частности, решения задачи на компьютере, это свойство существенно, поскольку, как правило, пользовательская ценность программы оказывается тем выше, чем больший круг однотипных задач она позволяет решить. Однако для построения алгоритмической теории это свойство не является существенным и обязательным.
Уточнение понятия алгоритма производится в рамках алгоритмических моделей. Модель определяет набор средств, использование которых допустимо при решении задачи, т.е. перечень элементарных шагов, способы определения следующего шага и т.д.
Алгоритм как абстрактная машина
алгоритмические процессы - это процессы, которые может осуществлять определенным образом устроенная машина, моделирующая тем самым выполнение отдельных операций человеком. Функционирование такой машины и есть выполнение некоторого алгоритма.
Абстрактная машина Поста состоит из бесконечной ленты, разделенной на равные секции и считывающе-записывающей головки. Каждая секция может быть либо пуста (т.е. в нее ничего не записано), либо заполнена (отмечена - т.е. в нее записана метка). Вводится понятие состояние ленты как информация о том, какие секции пусты, а какие отмечены (по-другому: состояние ленты - это распределение меток по секциям, т.е. это функция, которая каждому числовому номеру секции ставит в соответствие либо метку, либо знак «пусто»). Естественно, в процессе работы машины состояние ленты меняется. Состояние ленты и информация о положении головки характеризуют состояние машины.
Машина Тьюринга состоит из трех частей: ленты, считывающе-записывающей головки и логического устройства. Лента выступает в качестве внешней памяти; она считается неограниченной (бесконечной) - уже это свидетельствует о том, что машина Тьюринга является модельным устройством, поскольку ни одно реальное устройство не может обладать памятью бесконечного размера.
Как и в машине Поста, лента разбита на отдельные ячейки, однако, в машине Тьюринга неподвижной является головка, а лента передвигается относительно нее вправо или влево. Другим отличием является то, что она работает не в двоичном, а некотором произвольном конечном алфавите A={h, ah ..., ап} - этот алфавит называется внешним. В нем выделяется специальный символ - А, называемый пустым знаком - его посылка в какую-либо ячейку стирает тот знак, который до этого там находился, и оставляет ячейку пустой. В каждую ячейку ленты может быть записан лишь один символ. Информация, хранящаяся на ленте, изображается конечной последовательностью знаков внешнего алфавита, отличных от пустого знака.
Головка всегда расположена над одной из ячеек ленты. Работа происходит тактами (шагами). Система исполняемых головкой команд предельно проста: на каждом такте она производит замену знака в обозреваемой ячейке aj знаком а;. При этом возможны сочетания:
в обозреваемой ячейке знак не изменился;
хранившийся в ячейке знак заменяется пустым, т.е. стирается;
пустой знак заменяется непустым (с номером у в алфавите), т.е. производится вставка знака соответствует замене одного знака другим.
тезис Тьюринга Всякий алгоритм может быть задан посредством тьюринговой функциональной схемы и реализован в соответствующей машине Тьюринга.
Слово - это любая конечная последовательность знаков алфавита.
Число символов в слове называется его длиной.
Слово, длина которого равна нулю, называется пустым.
Слово s называется подсловом слова qt если q можно представить в виде q-rstf где rut- любые слова в том лее алфавите (в том числе и пустые).
Теперь можно определить понятие алгоритма (не являющееся строгим):
Алгоритмом в алфавите А называется эффективно вычислимая функция, областью определения которой служит какое-либо подмножество множества всех слов в алфавите А и значениями которой также являются слова в алфавите А.
В алгоритмах Маркова в качестве элементарного шага алгоритма принимается подстановка одного слова вместо другого. Пусть в алфавите А построено исходное слово Р, которое содержит подслово Рг (в общем случае таких подслов в исходном слове может быть несколько), а также имеется некоторое слово Рк в том же алфавите.
Подстановкой называется замена первого по порядку подслова Рг исходного слова Р на слово Рк. Обозначается подстановка Pr-^Pk.
Алгоритм в данной форме представления задается системой подстановок, которая представляет собой последовательность (список) подстановок. Если в этом списке имеются подстановки с левыми частями, которые входят в Р, то первая из них применяется к Р, в результате чего оно переходит в другое слово Pj. К нему вновь применяется схема подстановок и т.д. Процесс прекращается в двух случаях: либо в списке не нашлось подстановки с левой частью, входящей в Рп, либо при получении Рп была применена последняя подстановка.
Сопоставление алгоритмических моделей
Функция называется вычислимой, если имеется алгоритм, вычисляющий ее значение.
Множество называется разрешимым, если имеется алгоритм, который для любого объекта позволяет определить, принадлежит он данному множеству или нет.
Данные определения не являются формально строгими, т.е. не позволяют предсказать, окажется ли некоторая функция вычислимой или нет (или, что тоже самое: как по характеру функции определить, можно ли построить алгоритм для ее вычисления?). По этой причине весьма важным для построения теории алгоритмов был тезис Черча, который утверждал, что всякая частично рекурсивная функция является вычислимой. Другими словами, если функцию удалось построить с помощью 'суперпозиции, рекурсии и минимизации из простейших арифметических, то существует алгоритм, ее вычисляющий. Далее последовал тезис Тьюринга, утверждавший, что для всякой вычислимой функции можно построить машину Тьюринга, которая ее вычисляет. Можно доказать, что алгоритмы Поста также сводятся к алгоритмам, реализуемых с помощью частично рекурсивных функций. Справедливо и обратное утверждение. В частности задачи, решенные для машины Поста, являются примером реализации одной из простейших рекурсивных функций - функции непосредственного следования. Позднее была доказана теорема о сводимости одной алгоритмической модели к другой, следствием которой явились утверждения типа: «любую рекурсивную функцию можно вычислить с помощью соответствующей машины Тьюринга» или «для любой задачи, решаемой с помощью машины Тьюринга, существует решающий ее нормачъный алгоритм Маркова». Таким образом, все модели оказываются эквивалентными, в чем виден глубокий смысл, так как результат обработки информации, безусловно, определяется характером функции (алгоритмом) и входными данными, но не зависит от вида алгоритмической модели.
Проблема алгоритмической разрешимости.
Всякому алгоритму соответствует задача, для решения которой он был построен. Обратное утверждение в общем случае является неверным по двум причинам: во-первых, одна и та же задача может решаться различными алгоритмами; во-вторых, можно предположить (пока), что имеются задачи, для которых алгоритм вообще не может быть построен.
Как уже отмечалось, термин «алгоритм» появился в математике достаточно давно и использовался долго - под ним понималась процедура, позволявшая путем выполнения последовательности определенных элементарных шагов получать однозначный результат, не зависящий от того, кто эти шаги выполнял. Таким образом, само проведенное решение служило доказательством существования алгоритма. Однако был известен целый ряд математических задач, разрешить которые в общем виде не удавалось. Примерами могут послужить три древние геометрические задачи: о трисекции угла, о квадратуре круга и об удвоении куба - ни одна из них не имеет общего способа решения с помощью циркуля и линейки без делений.
Интерес математиков к задачам подобного рода привел к постановке вопроса: возможно ли, не решая задачи, доказать, что она алгоритмически неразрешима, т.е. что нельзя построить алгоритм, который обеспечил бы ее общее решение? Ответ на это вопрос важен, в том числе, и с практической точки зрения, например, бессмысленно пытаться решать задачу на компьютере и разрабатывать для нее программу, если доказано, что она алгоритмически неразрешима. Именно для ответа на данный вопрос и понадобилось сначала дать строгое определение алгоритма, без чего обсуждение его существования просто не имело смысла. Построение такого определения, как уже знаем, привело к появлению формальных алгоритмических систем, что дало возможность математического доказательства неразрешимости ряда проблем. Оно сводится к доказательству невозможности построения рекурсивной функции, решающей задачу, либо (что эквивалентно) к невозможности построения машины Тьюринга для нее, либо несостоятельности любой (какой-либо) другой модели из представленных в предыдущем пункте. Т.е. задача считается алгоритмически неразрешимой, если не существует машины Тьюринга (или рекурсивной функции, или нормального алгоритма Маркова), которая ее решает. Первые доказательства алгоритмической неразрешимости касались некоторых вопросов логики и самой теории алгоритмов. Оказалось, например, что неразрешима задача установления истинности произвольной формулы исчисления предикатов (т.е. исчисление предикатов неразрешимо) - эта теорема была доказана в 1936 г Черчем.
В 1946-47 гг. А.А. Марков и Э. Пост независимо друг от друга доказали отсутствие алгоритма для распознавания эквивалентности слов в любом ассоциативном исчислении.
В теории алгоритмов к алгоритмически неразрешимой относится «проблема остановки»: можно ли по описанию алгоритма (Q) и входным данным (х) установить, завершится ли выполнение алгоритма результативной остановкой? Эта проблема имеет прозрачную программистскую интерпретацию. Часто ошибки разработки программы приводят к зацикливанию - ситуации, когда цикл не завершается и не происходит завершения работы программы и остановки. Неразрешимость проблемы остановки означает, что нельзя создать общий (т.е. пригодный для любой программы) алгоритм отладки программ. Неразрешимой оказывается и проблема распознавания эквивалентности алгоритмов: нельзя построить алгоритм, который для любых двух алгоритмов (программ) выяснял бы, всегда ли они приводят к одному и тому же результату или нет.результатов: ИСТИНА или ЛОЖЬ. Этот класс можно считать разновидностью первого, поскольку предикат - это функция, принимающая два значения в зависимости от условия. Тем не менее, разделение этих классов задач полезно, так как приводит к двум важным понятиям теории алгоритмов - вычислимая функция и разрешимое множество.
Функция называется вычислимой, если имеется алгоритм, вычисляющий ее значение.
Множество называется разрешимым, если имеется алгоритм, который для любого объекта позволяет определить, принадлежит он данному множеству или нет.
5. Понятие и применение рекурсивных алгоритмов при решении задач. Сравнение рекурсивных и итерационных алгоритмов. Анализ сложности алгоритмов. Понятие вычислительной сложности (по времени и памяти). Асимптотические верхние и средние оценки для алгоритмов; сравнение алгоритмов по времени и памяти.
определения.
Рекурсивным называется объект, который частично определяется через самого себя Рекурсивные определения как мощный аналитический аппарат используются во многих областях науки, особенно в математике.
Формы рекурсивных процедур.
В общем случае любая рекурсивная процедура Rec включает в себя некоторое множество операторов S и один или несколько операторов рекурсивного вызова Р. Безусловные рекурсивный процедуры приводят к бесконечным процессам, и на эту проблему нужно обратить особое внимание, так как практическое использование процедур с бесконечным самовызовом невозможно. Такая невозможность вытекает из того, что для каждой копии рекурсивной процедуры необходимо выделять дополнительную область памяти, а бесконечной памяти не существует. Следовательно, главное требование к рекурсивным процедурам заключается в том, что вызов рекурсивной процедуры должен выполняться по условию, которое на каком-то уровне рекурсии станет ложным.
Если условие истинно, то рекурсивный спуск продолжается. Когда оно становится ложным, спуск заканчивается и начинается поочередный рекурсивный возврат из всех вызванных на данный момент копий рекурсивной процедуры.
Структура рекурсивной процедуры может принимать три разных формы:
1. Форма с выполнением действий до рекурсивного вызова (с выполнением действий на рекурсивном спуске).
2. Форма с вьшолнением действий после рекурсивного вызова (с вьшолнением действий на рекурсивном возврате)
3. Форма с вьшолнением действий как до, так и после рекурсивного вызова (с выполнением действий как на рекурсивном спуске, так и на рекурсивном возврате).
Все формы рекурсивных процедур находят применение на практике. Многие задачи, в том числе вычисление факториала, безразличны к тому, какая используется форма рекурсивной процедуры. Однако есть классы задач, при решении которых программисту требуется сознательно управлять ходом работы рекурсивных процедур и функций. Такими, в частности, являются задачи, использующие списковые структуры данных.
Пример рекурс алгоритмаЗадача о Ханойских башнях.
Отображение более сложных рекурсивных связей в алгоритмах покажем на примере задачи о Ханойских башнях. Эта интересная задача была сформулирована в 1883 году математиком Э.Люка. Многие учебные пособия по программированию используют ее как классический пример рекурсивного алгоритма.
Суть задачи состоит в следующем. Где-то далеко в окрестностях города Ханой стоят три башни. Одна из башен состоит из 97 золотых дисков, положенных друг на друга - как кольца в детской пирамиде. Диаметры всех дисков различны и уменьшаются от нижнего к верхнему. Необходимо перенести все диски с одной башни на другую. При этом диски можно переносить только по одному с любой башни на другую. Ставить диск на землю или надевать больший на меньший нельзя! Согласно легенде этой работой заняты монахи
из местного монастыря. День и ночь они заняты переносом дисков с башни на башню. Когда они закончат всю работу - наступит конец света. Кстати, это вполне похоже на правду: для перемещения N дисков на другой стержень (по одному, не кладя больший на меньший) нужно сделать 2n-1 перемещений, что легко следует по индукции.
Для определения подхода к решению поставленной задачи, рассмотрим общий случай с п дисками. Если мы сможем сформулировать решение для п дисков в терминах решения для n-1 диска, то поставленная проблема была бы решена, поскольку задачу для n-1 диска можно будет, в свою очередь, решить в терминах n-2 дисков и так далее до тривиального случая одного диска. А для случая одного диска решение получается элементарным. Нужно просто переместить один единственный диск со столбика А на столбик С.
Таким образом, если сформулировать решение для п дисков в терминах п-1 диска, то мы фактически получим алгоритм рекурсивной процедуры, с помощью которой можно легко достичь цели поставленной задачи. Рассмотрим словесное описание алгоритма. Если n=1, тогда переместить этот диск со столбика А на столбик С и остановиться. В противном случае, надо поступить следующим образом: 1. переместить верхние n-1 диск со столбика А на столбик В, используя столбик С как вспомогательный. 2. переместить оставшийся нижний диск со столбика А на столбик С. 3. переместить п-1 диск со столбика В на столбик С, используя столбик А как вспомогательный.
Можно с уверенностью сказать, что т акая последовательность действий даст корректное решение для любого значения п. Это вытекает из следующего. Если n=1, то корректность очевидна. Если n=2, то мы знаем, что уже имеем решение для случая (n-l)-ro диска, которое равно 1. аналогично, если n=3, мы снова имеем решение для (n-l)-ro диска, которое равно 2 и т.д.
Программа, которая решает поставленную задачу с помощью рекурсивной процедуры.
Program Hanoi_Towers;
Uses Crt;
Var n:Integer;
Procedure Move_Disks (n:Byte; Source, Dest, Tmp: Char);
{ n - число дисков на столбике Source}
{Source - исходный столбик}
{Dest - столбик, на который нужно переставить диски}
{Tmp - вспомогательный столбик}
begin
if n=l then
writeln ('Переставить диск номер 1 со столбика', Source, 'на столбик ',
Dest)
else begin
{переставляем n-1 верхних дисков с исходного столбика на} {вспомогательный, используя целевой диск как промежуточный}
Move_Disks (n-1, Source, Tmp, Dest);
Writeln ('переставить диск номер', п:1, 'со столбика', Source,
'на столбик', Dest);
{ переставляем все п-1 диск, расположенные на вспомогательном} {столбике, на целевой, используя исходный диск как промежуточный}
Move_Disks (n-1, Tmp, Dest, Source);
End End;
Begin
Write ('введите число дисков:');
Readln (n);
Writeln ('последовательность инструкций для решения задачи:');
Writeln;
Move_Disks (n, 'А', 'С, 'В');
End.
Результат работы программы для числа исходных дисков на столбике А, равного 4, будет таким:
Введите число дисков: 4
Последовательность инструкций для решения задачи:
Переставить диск номер 1 со столбика А на столбик В
Переставить диск номер 2 со столбика на А столбик С
Переставить диск номер 1 со столбика В на столбик С
Переставить диск номер 3 со столбика А на столбик В
Переставить диск номер 1 со столбика С на столбик А
Переставить диск номер 2 со столбика С на столбик В
Переставить диск номер 1 со столбика А на столбик В
Переставить диск номер 4 со столбика А на столбик С
Переставить диск номер 1 со столбика В на столбик С
Переставить диск номер 2 со столбика В на столбик А
Переставить диск номер 1 со столбика С на столбик А
Переставить диск номер 3 со столбика В на столбик С
Переставить диск номер 1 со столбика А на столбик В
Переставить диск номер 2 со столбика А на столбик С
Переставить диск номер 1 со столбика В на столбик С
Следует отметить аналогию между методом математической индукции и рекурсивным методом программирования.
Анализ сложных алгоритмов
Развитие и совершенствование компьютерной техники повлекло за собой создание разнообразных алгоритмов, обеспечивающих решение многочисленных прикладных задач, причем даже для однотипных задач создавалось (и создается) много алгоритмов (программ). Подобные алгоритмы ранее были названы эквивалентными. Однако для практики недостаточно знать, что решение некоторой задачи на компьютере в принципе возможно (т.е. проблема алгоритмически разрешима). Исполнение любого алгоритма требует определенного объема памяти компьютера для размещения данных и программы, а также времени центрального процессора по обработке этих данных - эти ресурсы ограничены и, следовательно, правомочен вопрос об эффективности их использования. Таким образом, в самом широком смысле понятие эффективности связано со всеми вычислительными ресурсами, необходимыми для работы алгоритма. Однако обычно под «самым эффективным» понимается алгоритм, обеспечивающий наиболее быстрое получение результата, поскольку в практических ситуациях именно ограничения по времени часто являются доминирующим фактором, определяющим пригодность того или иного алгоритма. По этой причине рассмотрим временную сложность алгоритмов.
Время работы алгоритма удобно выражать в виде функции от одной переменной, характеризующей «размер» конкретной задачи, т.е. объем входных данных, необходимых для ее решения. Такой подход удобен, поскольку сравнительная сложность задач может оцениваться через ее размер. Поскольку описание задачи, предназначенной для решения посредством вычислительного устройства, можно рассматривать в виде слова конечной длины, представленной символами конечного алфавита, в качестве формальной характеристики размера задачи можно принять длину входного слова. Например, если стоит задача определения максимального числа в некоторой последовательности из п элементов, то и размер задачи будет п, поскольку любой вариант входной последовательности можно задать словом из п символов.
Временная сложность алгоритма - это функция, которая каждой входной длине слова п ставит в соответствие максимальное (для всех конкретных однотипных задач длиной п) время, затрачиваемое алгоритмом на ее решение.
При этом, безусловно, предполагается, что во всех задачах используется одинаковая схема кодирования входных слов.
Различные алгоритмы имеют различную временную сложность и выяснение того, какие из них окажутся достаточно эффективны, а какие нет, определяется многими факторами. Однако теоретики, занимающиеся разработкой и анализом алгоритмов, для сравнения эффективности алгоритмов предложили простой подход, позволяющий прояснить ситуацию. Речь идет о различии между полиномиальными и экспоненциальными алгоритмами.
Полиномиальным называется алгоритм, временная сложность которого выражается некоторой полиномиальной функцией размера задачи п.
Алгоритмы, временная сложность которых не поддается подобной оценке, называются экспоненциальными.
Различие между указанными двумя типами алгоритмов становятся особенно заметными при решении задач большого размера., Время обработки экспоненциальных алгоритмов при одинаковых размерах задач (превышающих 20) намного выше, чем у полиномиальных; во-вторых, скорость нарастания времени обработки с увеличением размера задачи у экспоненциальных алгоритмов значительно выше, чем у полиномиальных. Различие между обоими типами алгоритмов проявляются еще более убедительно, если проанализировать влияние увеличения быстродействия компьютера на время исполнения алгоритма. В таблице показано, насколько возрастают размеры наибольшей задачи, решаемой за единицу машинного времени, если быстродействие компьютера вырастет в 100 и 1000 раз. Из таблицы видно, что, например, для экспоненциального алгоритма с функцией сложности f(n)=2a рост скорости вычислений в 1000 раз приводит лишь к тому, что размер наибольшей задачи возрастает всего на 10 единиц, в то время как для функции f(n)^n5 она возрастает почти в 4 раза. подобно тому, как существуют алгоритмически неразрешимые задачи, существуют и задачи объективно сложные, т.е. такие, трудоемкость которых невозможно уменьшить совершенствованием компьютера. Задача считается труднорешаемой, если для нее не удается построить полиномиального алгоритма. Это утверждение не является категорическим, поскольку известны задачи, в которых достаточно эффективно работают и экспоненциальные алгоритмы. Примером может служить симплекс-метод, который
успешно используется при решении задач линейного программирования, имея функцию сложности f(n)=2a. Однако подобных примеров не очень много, и общей следует признать ситуацию, что эффективно исполняемыми можно считать полиномиальные алгоритмы с функциями сложности пу п или п. Например, при решении задачи поиска нужного данного из п имеющихся в худшем варианте сложность равна п; если же оценить среднюю трудоемкость (продолжительность поиска), то она составит (п + 1)12 - в обоих случаях функция сложности оказывается линейной п. Задача ранжирования, т.е. расстановки в заданном порядке п однотипных данных приводит к полиному 2-й степени; сложность задачи вычисления определителя системы п линейных уравнений с п неизвестными характеризуется полиномом 3-й степени. Повышение быстродействия элементов компьютера уменьшает время исполнения алгоритма, но не уменьшает степень полинома сложности. Следовательно, решению практической задачи на компьютере должна предшествовать оценка ее сложности и доказательство того, что задача решаема за приемлемое время.
Вычислить точное время работы алгоритма оказывается невозможным. Это время помимо всего прочего зависит от характеристик реальной ЭВМ, на которой выполняется программа. Обычно время выполнения алгоритма считают приближенно. Более того, формулы для времени работы обьмно содержат некоторые числовые константы, значение которых можно определить лишь опытным путем. Даже такие оценки позволяют довольно часто выбрать один наилучший алгоритм. В других же случаях с помощью оценок времени работы можно отбросить заведомо медленные алгоритмы, а лучший из оставшихся выбрать с помощью измерения фактического времени работы программ. Остановимся на вопросе о выборе такой характеристики исходных данных, которая определяла бы время работы программы. Эта характеристика называется размером задачи. Для разных задач на время решения влияют разные свойства исходных данных. Так, для задач типа поиска минимума или упорядочивания заданных чисел, где каждое число рассматривается как единое целое, размером задачи является количество исходных чисел. Для задачи разложения на простые сомножители размером естественно считать величину числа. Выбор размера задачи основан на некотором, хотя бы общем представлении об алгоритме решения.
Следующий важный момент при оценке времени работы - отыскание тех частей программы, выполнение которых занимает основную долю всего времени работы. Известен экспериментальный факт, справедливый для подавляющего большинства программ: основная часть времени работы тратится на выполнение очень небольшой части текста программы. Такая часть программы называется внутренним циклом. Так как с самого начала мы требуем приближенной оценки времени работы, поэтому всей остальной частью программы можно пренебречь. Более детальную информацию о времени работы можно получить по результатам измерения фактического времени работы программы для различных исходных данных. С помощью этих экспериментальных данных можно оценить неизвестные постоянные, входящие в формулу
Можно сказать, что алгоритм - это точно определенная (однозначная) последовательность простых (элементарных) действий, обеспечивающих решение любой задачи из некоторого класса.
Однако данное утверждение нельзя принять в качестве строгого определения алгоритма, поскольку в нем использованы другие неопределяемые понятия -однозначность, элементарность и др.
Понятие можно уточнить, указав перечень общих свойств, которые характерны для алгоритмов. К ним относятся:
Дискретность алгоритма означает, что алгоритм разделен на отдельные шаги (действия), причем, выполнение очередного шага возможно только после завершения всех операций на предыдущем шаге. При этом набор промежуточных данных конечен и он получается по определенным правилам из данных предыдущего шага.
Детерминированность алгоритма состоит в том. Что совокупность промежуточных величин на любом шаге однозначно определяется системой величин, имевшихся на предыдущем шаге. Данное свойство означает, что результат выполнения алгоритма не зависит от того, кто (или что) его выполняет (т.е. от исполнителя алгоритма), а определяется только входными данными и шагами (последовательностью действий) самого алгоритма.
Элементарность шагов: закон получения последующей системы величин из предыдущей должен быть простым и локальным. Какой шаг можно считать элементарным, определяется особенностями исполнителя алгоритма.
Направленность алгоритма: если способ получения последующих величин из каких-либо исходных не приводит к результату, то должно быть указано, что следует считать результатом алгоритма.
Массовость алгоритма: начальная система величин может выбираться из некоторого множества
6. О(n) алгоритмы сортировки (например, выбором и вставкой); оценки сложности, лучшие и худшие случаи. О(nlogn) алгоритмы сортировки (например, быстрая сортировка, метод слияния); оценка сложности; другие методы сортировки (метод Шелла и Хоара); сравнение алгоритмов сортировки. Последовательный и бинарный поиск.
Сортировкой называют процесс перегруппировки заданной последовательности объектов в некотором определённом порядке.
Методы внутренней сортировки обеспечивают большую гибкость при построении структур данных и доступа к ним, внешние же методы обеспечивают достижение нужного результата в условиях ограниченных ресурсов.
Методы сортировки служат хорошей иллюстрацией базовых концепций анализа алгоритмов, т.е. оценки качества алгоритмов, что позволяет разумно делать выбор среди, казалось бы, равноценных методов.
Пусть a1,a2,…,an– перестановка множества {1,2,…,n}.
Если i<j и ai<aj, то пара (ai,aj) называется инверсией перестановки.
Например, перестановка 3142 имеет 3 инверсии: (3,1) (3,2) (4,2).
Каждая инверсия – это пара элементов, «нарушающих порядок»; единственная перестановка, не содержащая инверсий, - это рассортированная перестановка 1 2 … n.
Перестановкой конечного множества называется некоторое расположение его элементов в ряд.
Перестановки важны при изучении алгоритмов сортировки, так как они служат для представления неупорядоченных исходных данных. Чтобы исследовать эффективность различных методов сортировки нужно уметь подсчитывать количество перестановок, которые вынуждают повторять некоторый шаг алгоритма определённое число раз.
Рассмотрим внутреннюю сортировку, когда число записей, подлежащих сортировке, достаточно мало, так что весь процесс можно провести в оперативной памяти компьютера, обладающий высоким быстродействием.
В одних случаях может понадобиться физически представлять записи в памяти так, чтобы их ключи были упорядочены; в других можно обойтись вспомогательной таблицей некоторого вида, определяющей перестановку.
Сортировка путём вставки.
(Метод простых вставок или прямого включения) Пусть 1≤j≤N и записи R1,…,Rj-1 уже размещены так, что K1≤K2≤…≤Kj-1 .
Будем сравнивать по очереди Kj с Kj-1 ,Kj-2 , … до тех пор, пока не обнаружим, что запись Rj следует вставить между Ri и Ri+1 ; тогда подвинем записи Ri+1 , … ,Rj-1 на одну позицию вверх и поместим новую запись в позицию i+1. Удобно совмещать операции сравнения и перемещения.
Поскольку запись Rj как бы «погружается» на положенный ей уровень, этот способ часто называют присваиванием или погружением.
Процесс просеивания может закончиться при выполнении одного из двух условий:
Найден элемент Rj с ключом, меньшим чем ключ у K
Достигнут левый конец готовой последовательности.
Словесное описание алгоритма
Записи R1,R2,…,RN пере размещаются на том же месте. После завершения сортировки их ключи будут упорядочены K1≤…≤KN.
S1. [Цикл по j]. Выполнить шаги от S2 до S5 при j=2,3,…N и после этого завершить выполнение процедуры.
S2. [установка i, K, R]. Присвоить i←j-1, K←Kj, R←Rj.
S3. [Сравнение K:Ki]. Если K ≥ Ki, то перейти к S5 (Нашли искомое место для записи R).
S4. [Перемещение Ri]. Присвоить Ri+1←Ri , i←i-1. Если i>0, то возврат к S3. Если i=0, то K- наименьший из рассмотренных ключей, и К должно занять первую позицию.
S5. [Перенос R на Rj+1]. Присвоить Ri+1 значение R.
Сортировка посредством выбора
Этот приём основан на следующих принципах:
Выбирается элемент с наименьшим ключом
2. Он меняется местами с первым элементом R1
3. Затем этот процесс повторяется с оставшимися n-1 элементами, n-2 элементами и так далее до тех пор, пока не останется один, самый большой элемент.
Этот метод требует наличие всех исходных элементов до начала сортировки, а элементы вывода порождает последовательно, один за другим, Картина, по существу, противоположна картине, возникающей при использовании метода вставок, в котором исходные записи поступают последовательно, но вплоть до завершения сортировки об окончательном результате ничего не известно.
О(nlogn) алгоритмы сортировки.Обменная сортировка.
Это семейство алгоритмов сортировки, предусматривающих системный обмен местами между элементами пар, в которых нарушается упорядоченность, до тех пор, пока таких пар не останется.
(Пузырьковая сортировка).
Заключается в сравнении двух соседних элементов массива, в результате которого меньшее число (более легкий пузырёк) перемещается на одну позицию влево. Обычно такой просмотр организуют с конца массива и после первого прохода самое маленькое число перемещается на первое место. Затем все повторяется от конца массива до второго элемента и так далее.
Метод назван «методом пузырька», потому что маленькие элементы, подобно пузырькам, «всплывают» на соответствующую позицию.
Время работы этого алгоритма определяется тремя параметрами: числом проходов А, числом обменов В и числом сравнений С. Улучшение этого алгоритма происходит само собой. Из примера видно, что три последовательных элемента не влияют на порядок элементов из-за того, что они уже отсортированы. Один из примеров улучшения этого метода – запоминать, были или нет перестановки в процессе некоторого прохода.
Сортировка методом слияния.(двухпутевое слияние)
Слияние означает объединение двух или более упорядоченных массивов в один упорядоченный массив.
Самый простой способ сделать это – сравнить два наименьших элемента, вывести наименьшее из них и повторить процедуру
Слияние означает объединение двух или более упорядоченных массивов в один упорядоченный массив.
Самый простой способ сделать это – сравнить два наименьших элемента, вывести наименьшее из них и повторить процедуру
структура
М1. Установить i←1, j←1, k←1.
М2. Если xi ≤ yj,, перейти к М3, в противном случае к М5.
М3. Установить zk ← xi, k ← k+1, i←i+1. Если i ≤ m , вернуться к М2.
М4. Установить (zk, …, z(m+n)) ← (yj, …, yn) и завершить выполнение.
М5. Установить zk ← yj,, , k ← k+1, j←j+1. Если j≤n, вернуться к шагу М2.
М6. Установить (zk, …, z(m+n))←(xi, …,xm) и завершить алгоритм.
А) Алгоритмы быстрой сортировки. (Сортировка Хоара или сортировка с помощью разделения)
Этот алгоритм является примером использования рекурсии. Он был разработан в 1962 году, профессором Оксфордского университета Хоаром. (Основан на алгоритме сортировки обменами).
Принцип метода: для достижения наилучшей эффективности сначала лучше производить перестановки на большие расстояния. Выберем наугад какой-либо элемент (х) и будем просматривать слева массив до тех пор, пока не обнаружим элемент Ri> x, затем будем просматривать массив справа, пока не встретим Rj<x. Теперь поменяем их местами и продолжим процесс просмотра и обмена, пока оба просмотра не встретятся в середине массива. В результате массив окажется разбитым на левую часть с ключами ≤ x, и правую – с ключами ≥ x.
Таким образом, относительно значения x массив получается отсортированным, но левая и правая части ещё не упорядочены.
Сортировка с помощью включений с уменьшающимися расстояниями (Сортировка Шелла)
Если желательно получить метод, существенно превосходящий по скорости метод простых вставок, необходимо, чтобы записи могли бы перемещаться большими скачками.
Его суть: сначала отдельно группируются и сортируются элементы, отстоящие друг от друга на n/2 (n – количество элементов массива). Каждая группа состоит из 2 элементов. Если n/2=4 , такой процесс называется четвертной сортировкой. После первого прохода элементы перегруппировываются – теперь каждый элемент группы отстоит от другого на n/4 позиции – и вновь сортируются. Если n/4=2 то этот процесс называется двойной сортировкой. Процесс завершается проходом, во время которого сортируются все n записей.
В каждой из промежуточных стадий сортировки участвуют либо сравнительно короткие массивы, либо уже сравнительно хорошо упорядоченные массивы, поэтому на каждом этапе можно пользоваться методом простых вставок и сортировка выполняется довольно быстро.
Поиск элементов в массивах – одно из наиболее часто встречающихся в программировании действий.
В несортированном алгоритме поиск осуществляется последовательным перебором всех элементов массива. Поиск производится сравнением элементов массива с образцом. При совпадении элемента массива с образцом, выводится номер этого элемента. Если элементов, удовлетворяющих образцу больше чем один, выводятся номера всех этих элементов. По найденному номеру из другого массива можно получить дополнительную информацию об искомом элементе. Например, поиск номера абонента телефонной сети по адресу.
В сортированном массиве поиск осуществляется делением исходного массива на два равных массива, один из которых содержит первую половину всех элементов, а второй - вторую половину. Далее выясняется, в какой из этих половин может находиться искомый элемент. Для этого образец сравнивается с крайними элементами массива, и выбирают ту половину, в которой образец находится между крайними элементами.
Последовательный (линейный) поиск.
Если нет никакой дополнительной информации о разыскиваемых данных, то очевидный подход используется последовательный просмотр массива с увеличением шаг за шагом той его части, где желаемого элемента не обнаружено.
Условия окончания поиска таковы:
Элемент найден, т.е. Ki=K.
Весь массив просмотрен и совпадения не обнаружено.
Бинарный поиск (поиск делением пополам).
Поиск можно сделать значительно более эффективным, если данные будут упорядочены. Основная идея – выбрать случайно некоторый элемент, предположим, Ki, и сравнить его с аргументом поиска. Если он равен K, то поиск заканчивается, если он меньше K, то мы заключаем, что все элементы с индексами <=i можно исключить из дальнейшего поиска. Если же он >K, то исключаются индексы >=i. Здесь используем два указателя l и u, которые указывают верхнюю и нижнюю границы поиска.