Смекни!
smekni.com

Методические указания к выполнению контрольных работ по дисциплине "Основы программирования" (стр. 5 из 40)

2. Определенность. Каждый шаг алгоритма должен быть точно определен. Действия, которые нужно выполнить, должны быть строго и недвусмысленно определены для каждого возможного случая. Чтобы преодолеть это затруднение, для описания алгоритмов были разработаны формально определенные языки программирования, или машинные языки, в которых каждый оператор имеет строго определенное значение.

Определение: метод вычислений, выраженный на языке программирования, называется программой.

Рассмотрим в качестве примера алгоритм Е. Применительно к шагу Е1 критерий определенности означает, что читатель обязан точно понимать, что значит разделить т на п и что такое остаток. Но в действительности нет никакого общепринятого соглашения по поводу того, что это означает, если m и п не являются целыми положительными числами. Каким будет остаток от деления -8 на -p ? Что понимать под остатком от деления 59/13 на нуль? Поэтому в данном случае критерий определенности означает следующее: мы должны быть уверены, что в каждом случае выполнения шага Е1 значениями т и п всегда будут целые положительные числа. Если сначала по предположению это верно, то после шага Е1 r – это целое неотрицательное число; при условии перехода к шагу ЕЗ оно является также ненулевым. Таким образом, поставленное требование выполнено и т и п – это действительно целые положительные числа.

3. Ввод. Алгоритм имеет некоторое (возможно, равное нулю) число входных данных, т.е. величин, которые задаются до начала его работы или определяются динамически во время его работы. Эти входные данные берутся из определенного набора объектов. Например, в алгоритме Е есть два входных значения, а именно m и п, которые принадлежат множеству целых положительных чисел.

4. Вывод. У алгоритма есть одно или несколько выходных данных, т.е. величин, имеющих вполне определенную связь с входными данными. У алгоритма Е имеется только одно выходное значение, а именно п, получаемое на шаге Е2. Это наибольший общий делитель двух входных значений.

Можно легко доказать, что это число действительно является наибольшим общим делителем. После шага Е1 имеем:

,

где q – некоторое целое число.

Если r = 0, то т кратно п и, очевидно, в этом случае n – наибольший общий делитель для m и п.

Если r # 0, то любой делитель обоих чисел m и п должен быть также делителем для

,

а любой делитель для п и r – также делителем для:

.

Таким образом, множество делителей чисел {т, п} совпадает с множеством делителей чисел {п, r}. Следовательно, пары чисел {т, п} и {п, r} имеют один и тот же наибольший общий делитель. Таким образом, шаг ЕЗ не изменяет ответа исходной задачи.

5. Эффективность. Алгоритм обычно считается эффективным, если все его операторы достаточно просты для того, чтобы их можно было точно выполнить в течение конечного промежутка времени с помощью карандаша и бумаги. В алгоритме Е используются только следующие операции: деление одного целого положительного числа на другое, сравнение с нулем и присвоение одной переменной значения другой. Эти операции являются эффективными, так как целые числа можно представить на бумаге с помощью конечного числа знаков и так как существует по меньшей мере один способ деления одного целого числа на другое – «алгоритм деления». Но те же самые операции были бы неэффективными, если бы они выполнялись над действительными числами, представляющими собой бесконечные десятичные дроби, либо над величинами, выражающими длины физических отрезков прямой, которые нельзя измерить абсолютно точно. Приведем еще один пример неэффективного шага: «Если 4 – это наибольшее целое n, при котором существует решение уравнения wn + xn + yn = zn для целых положительных чисел w, x, y и z, то перейти к шагу Е4». Подобная операция не может считаться эффективной до тех пор, пока кто-либо не разработает алгоритм, позволяющий определить, действительно ли 4 является наибольшим целым числом с требуемым свойством.

Попробуем сравнить понятие «алгоритм» с рецептом из кулинарной книги. Предполагается, что рецепт обладает свойством конечности (хотя и говорят, что «кто над чайником стоит, у того он не кипит»), имеет

· входные данные (такие, например, как яйца, мука и т.д.),

· выходные данные (обед «на скорую руку» и т.п.),

· но хорошо известно, что ему не хватает определенности.

Инструкции из кулинарных рецептов очень часто бывают неопределенными, например: «Добавьте щепотку соли». «Щепотка» определяется как количество, «меньшее 1/8 чайной ложки», и что такое соль, вероятно, тоже известно всем. Но куда именно нужно добавить соль – сверху? сбоку? Инструкции «Слегка потрясите, пока смесь не станет рассыпчатой» и «Подогрейте коньяк в маленькой кастрюльке» будут вполне понятны опытному повару, но они не годятся для алгоритма. Алгоритм должен быть определен настолько четко, чтобы его указаниям мог следовать даже компьютер. Тем не менее, программист может многому научиться, прочитав хорошую поваренную книгу.

Следует отметить, что для практических целей ограничение, состоящее в конечности алгоритма, в сущности, является недостаточно жестким. Используемый на практике алгоритм должен иметь не просто конечное, а достаточно ограниченное, разумное число шагов.

Например, алгоритм определения того, может ли игра в шахматы всегда быть выиграна белыми при условии, что не было сделано ни одной ошибки. Этот алгоритм позволил бы решить проблему, представляющую огромный интерес для тысяч людей, но можно биться об заклад, что окончательный ответ на данный вопрос мы не узнаем никогда. Все дело в том, что для выполнения указанного алгоритма требуется невероятно большой промежуток времени, хотя сам алгоритм и является конечным.

На практике нам нужны не просто алгоритмы, а хорошие алгоритмы в широком смысле этого слова. Одним из критериев качества алгоритма является время, необходимое для его выполнения; данную характеристику можно оценить по тому, сколько раз выполняется каждый шаг. Другими критериями являются адаптируемость алгоритма к различным компьютерам (или переносимость, мобильность программ, как на языке С++), его простота, изящество и т.д.

Часто решить одну и ту же проблему можно с помощью нескольких алгоритмов и нужно выбрать наилучший из них. Таким образом, мы попадаем в чрезвычайно интересную и крайне важную область анализа алгоритмов. Предмет этой области состоит в том, чтобы для заданного алгоритма определить рабочие характеристики.

В качестве примера давайте исследуем с этой точки зрения алгоритм Евклида. Предположим, нам нужно решить следующую задачу: «Пусть задано значение n, а т может быть любым целым положительным числом. Тогда чему равно среднее число Тпвыполнений шага Е1 алгоритма Е?».

Прежде всего необходимо убедиться в том, что задача имеет смысл, поскольку нам предстоит найти среднее при бесконечно большом количестве значений т. Но совершенно очевидно, что после первого выполнения шага Е1 значение будет иметь только остаток от деления т на п. Поэтому все, что мы должны сделать для нахождения значения Тп , – это испытать алгоритм для m = 1, m = 2, ..., m = п, подсчитать суммарное число выполнений шага Е1 и разделить его на п.

А теперь рассмотрим еще один важный вопрос, касающийся поведения Тпкак функции от п: можно ли ее аппроксимировать, например, функцией

или
?

На самом деле это чрезвычайно сложная и интересная математическая проблема, которая еще не решена окончательно. Можно доказать, что при больших значениях п Тп ведет себя, как функция

,

т.е. она пропорциональна натуральному логарифму п. Заметим, что коэффициент пропорциональности k нельзя просто взять и угадать; чтобы определить его, нужно затратить определенные усилия.

Для обозначения области подобных исследований используется термин анализ алгоритмов. Основная идея заключается в том, чтобы взять конкретный алгоритм и определить его количественные характеристики. Время от времени мы будем также выяснять, является ли алгоритм оптимальным в некотором смысле. Теория алгоритмов – это совершенно другая область, в которой, в первую очередь, рассматриваются вопросы существования или не существования эффективных алгоритмов вычисления определенных величин.

До сих пор наше обсуждение алгоритмов носило достаточно общий характер, и, вероятно, «математически настроенный» читатель утвердился в мысли, что все предыдущие комментарии представляют собой очень шаткий фундамент для построения какой-либо теории алгоритмов. Поэтому давайте подведем итог данного раздела, кратко описав метод, с помощью которого понятие алгоритма можно строго обосновать в терминах математической теории множеств.