Кузин С.Г. Основы алгоритмизации - файл n1.doc

приобрести
Кузин С.Г. Основы алгоритмизации
скачать (2249.5 kb.)
Доступные файлы (1):
n1.doc2250kb.11.06.2012 05:36скачать

n1.doc






Основы алгоритмизации. Методическое руководство для самостоятельного изучения. / Сост. С.Г.Кузин. Н.Новгород - ННГУ, 2004

Методическое руководство можно разделить на три основные части.

В первой части (раздел 1) излагается точка зрения на алгоритм как способ вычисления функционального преобразования в заданной точке.

Во второй части (раздел 2) подробно обсуждается язык блок - схем как один из возможных способов записи алгоритма.

Третья часть (разделы 3 - 5) посвящена рассмотрению типовых прикладных задач обработки последовательности данных.

В приложении приводятся блок - схемы рассматриваемых алгоритмов. Рисунки блок - схем изготовлены с помощью программной системы "Редактор алгоритмов" разработанной на кафедре ИИСГео под руководством доцента С.Г. Кузина.

Данное издание служит методической поддержкой курса лекций "Основы алгоритмизации", который читается в третьем семестре для специализации "Информационные системы для обеспечения финансово - кредитной, юридической, управленческой и издательской деятельности" (специальность 07.19.00) для очного и заочного отделений факультета ВМК ННГУ. Этот курс не заменяет собой курс лекций по конкретным языкам программирования и читается параллельно с ним.

Методическая разработка может быть полезна всем, кто начинает изучать методы алгоритмизации и программирование.
Составитель: доцент кафедры МО ЭВМ С.Г.Кузин.

Рецензент: доц. каф. МЛиВА

Таланов В.А.
Нижегородский государственный университет им. Н.И.Лобачевского,

2004 г.

Функциональное преобразование данных и алгоритм.

Преобразование данных как функциональное преобразование.


Мы утверждаем, что решение любой прикладной задачи сводится к тому или иному преобразованию данных. Такое преобразования данных, явно или неявно, представляется в виде функционального преобразования (функции):

F: D® R. (0)

Каждое преобразование определяет соответствие заданного априори набора исходных данных dОD и неизвестного априори набора результирующих данных rОR. Множество D является областью определения функционального преобразования (областью допустимых наборов исходных данных). Множество R является областью значения функции (областью наборов результирующих данных). Значение функционального преобразования при заданном наборе исходных данных d обозначается как:

F(d) или F(d) = r. (0)

Примечание. Если область определения и область значений функционального преобразования (функции) совпадают, то такое функциональное преобразование принято называть операцией. Это, прежде всего, относится к бинарным функциям - операциям сложения, вычитания, умножения и деления вещественных чисел

Набор данных - совокупность единиц данных. Единица данных - символьная конфигурация, обозначающая характеристику сущности реального или абстрактного мира. Примеры таких сущностей и характеристик: возраст человека, площадь треугольника, цвет предмета, скорость протекания процесса, ситуация на шахматной доске.

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

Алгоритм преобразования данных (алгоритм решения прикладной задачи) мы определяем как однозначно определенный способ вычисления значения функционального преобразования (1) при любом заданном допустимом наборе исходных данных d.

Учитывая тот факт, что наборы данных представляются конфигурациями символов, алгоритм - это некоторый способ получения символьной конфигурации rОR по заданной символьной конфигурации dОD.

Таким образом, конкретный алгоритм - это конкретный способ преобразования символьных конфигураций. И особый вопрос, что эти символьные конфигурации обозначают. Если символьные строки обозначают числа, мы имеем дело с единицами данных - числами. В этом случае функциональное преобразования (1) является численной функцией и мы имеем дело с вычислительным алгоритмом. Например, функция зависимости площади треугольника от размеров его сторон.

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

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

Для того чтобы алгоритм можно было воспринимать и исполнять, он должен быть записан на каком - либо формальном языке. Существует несколько формальных языков записи алгоритмов. Назовем два наиболее известных: язык блок - схем и язык программирования. В любом случае, запись алгоритма предполагает, что существует исполнитель алгоритма, который это описание может "понять" и выполнить Рис. 1.



Рис. 1. Программная и электронная модели вычислений

Если записью алгоритма является блок - схема, то в качестве исполнителя подразумевается человек. Он может проверить правильность этой блок - схемы, исполняя ее для некоторых исходных наборов данных (ручная отладка алгоритма). Запись алгоритма на языке программирования исполняется компьютером. Предполагается, что компьютер может выполнить предписанные этой программой действия по преобразованию данных. Таким образом, запись алгоритма в виде программы является, по сути дела программной моделью вычислений.

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

Алгоритм, как способ преобразования данных существенным образом зависит от формы определения функционального преобразования - функции (1). Таким образом, прежде чем конструировать алгоритм вычисления значения функции, необходимо определиться с формой представления этой функции.

Табличная форма определения функции.


С теоретической точки зрения универсальным способом задания функционального преобразования (функции) является функциональное отношение или график функции.

Пусть X1,X2,...,Xi,...,Xn,R- любые множества. Пусть также
M= X1ґX2ґ...ґXiґ...ґXnґR - декартово произведение этих множеств. Отношением r называется любое подмножество этого декартова произведения:

(0)

Таким образом, отношение - это конечное или бесконечное множество строк следующего вида:

(0)

Уберем из отношения r последний столбец. Получим множество:

j = 1,2,3,...; (0)

Отношение функционально, если для каждой последовательности:

; (0)

в отношении r имеется единственная строка:

(0)

С каждым функциональным отношением (4) связано функциональное преобразование (функция) n аргументов:

(0)

Значение функции в произвольной точке обозначается как:

или (0)

Функциональное отношение (4) также называется графиком функции. Элемент xi в (9) называется переменной или аргументом.

График функции, являющийся конечным множеством строк, принято называть таблицей функции.

Замечание. Множества Xi и R совершенно не обязательно являются числовыми множествами. Более того, элементами этих множеств могут быть структуры: вектора, матрицы, записи, деревья, графы и т.д.

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

Допустимые значения аргументов этой функции: колер1 = {красный, нет}; колер2{синий, нет}; колер3 = {желтый, нет}. Область значений функции: R = {черный, желтый, синий, зеленый, красный, оранжевый, фиолетовый, белый}.


Область D определения функции Колер

R

колер1

колер2

колер3

сложный колер

нет

нет

нет

черный

нет

нет

желтый

желтый

нет

синий

нет

синий

нет

синий

желтый

зеленый

красный

нет

нет

красный

красный

нет

желтый

оранжевый

красный

синий

нет

фиолетовый

красный

синий

желтый

белый


Это табличная форма определения функции трех аргументов:

Колер(колер1,колер2,колер3).

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

Алгоритм вычисления значения функции, представленной в табличной форме, очевиден и сводится к поиску записи в таблице по заданному ключу:

  1. для заданных значений аргументов (ключ поиска): x1,x2,...,xn, найти строку в таблице, первые n полей которой содержат этот ключ;

  2. выдать в качестве результата содержимое n+1-го поля найденной строки.

Этот алгоритм относится к разряду универсальных, так как работает на любой таблице.

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

Замечание. Такое условие выполняется для любой логической (булевской) функции n переменных, любой аргумент которой имеет всего два значения, а число значений функции также равно двум.

Аналитическая форма определения логической функции.


Если функция вещественного переменного используются для описания характеристик предметов (процессов), то логическая функция формализует процесс принятия решения. В математической логике доказана теорема, которая утверждает, что любая логическая (булевская) функция может быть выражена через три элементарные логические функции - дизъюнкцию, конъюнкцию и отрицание. Таким образом, теоретически, любая логическая функция может быть представлена в виде композиции этих трех функций - операций. Говорят также, что в этом случае функция представлена в аналитическом виде.

В качестве примера формализуем принятие решения о приеме человека на работу, которая требует высшего образования, знания компьютера и/ или английского языка. Введем три логические переменные:

Тогда, условия приема на работу формализуются в виде логической функции (10):

(0)

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

<операция отношения> (0)

Здесь, a и b - < константа, переменная или функция >.

Пример логической функции, включающей в себя два отношения: (x<5)Ъ(x>10).

Аналитическую запись логической функции представленную в виде строки символов называют логическим выражением. Логическое выражение используется в качестве условия в управляющих конструкциях выбора (оператор if).

Замечание. Частным случаем логического выражения является одно отношение.

Предписание на вычисление логической функции оформляется в виде логического оператора присваивания:

<результирующая переменная>: = <логическое выражение>. (0)

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

Алгоритм вычисления логического выражения, хорошо известен. Он реализуется исполнителем, способным вычислять значения дизъюнкции, конъюнкции и отрицания. Такой исполнитель является частью центрального процессора компьютера и являет собой аналоговую модель вычисления трех элементарных логических функций - операций. Исполнение алгоритма вычисления логического выражения - последовательное исполнение этих операций с учетом приоритетов и скобок. Это также универсальный алгоритм, так как он применим к любой логической функции, записанной в аналитическом виде.

Аналитическая форма определения вещественной функции.


По причине бесконечности числа значений вещественного аргумента, определение вещественной функции n вещественных аргументов в виде конечной таблицы невозможно:

F: RґRґ...ґR ®R, здесь R - бесконечное множество; (0)

Значение этой функции обозначается в виде:

(0)

Однако значения некоторых "хороших" функций можно представить в виде композиции конечного числа элементарных функций. В этом случае мы имеем вещественную функцию, представленную в аналитическом виде. К числу элементарных функций относятся: четыре функции - арифметические операции (сложение, вычитание, умножение, деление); элементарные математические функции (логарифм, экспонента,....); элементарные тригонометрические функции (синус, косинус,...). Аналитическую запись функции в виде строки символов принято называть арифметическим выражением.

Замечание. Частным случаем арифметического выражения является одна переменная (одна константа).

Например, хорошо известно аналитическое определение функции, определяющей зависимость площади треугольника от размеров его сторон (формула Герона):

(0)

Предписание на вычисление функции, представленной в аналитическом виде, задается в виде оператора присваивания:

<результирующая переменная> : = <арифметическое выражение>. (0)

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

Операторы присваивания для вычисления (15) приведены ниже:

p := (a+b+c)/2; s := sqr((p-a)*(p-b)*(p-c)). (0)

Другой пример, зависимость напряжения на конденсаторе (Рис. 2) представляется функцией (18), заданной в аналитической форме:

(0)


Рис. 2. Пример электронной схемы

Соответствующий оператор присваивания:

U : = E(1-exp(t/R*C)). (0)

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

Определение элементарной функции в форме ряда Тейлора.


Элементарные математические и тригонометрические функции представляются в форме ряда Тейлора. Например:

(0)
Таким образом, для вычисления любого арифметического выражения (вещественной функции, представленной в аналитическом виде) необходим исполнитель, способный выполнять только четыре арифметических операции (вычислять функции сложения, вычитания, умножения и деления).

Аналоговая модель двоичного сложения и вычитания.


При компьютерных вычислениях числа представляются в двоичном коде. И центральный процессор компьютера должен выполнять операции двоичного сложения и вычитания.

В качестве примера рассмотрим что происходит при сложении двух двоичных кодов в разряде i.



Здесь, ai, bi - операнды сложения; ci - результат сложения; pi, pi-1 - перенос из предыдущего разряда и перенос в следующий разряд и соответственно.

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

(0)

0)

Примечание. Подобная аналитическая запись носит название дизъюнктивной нормальной формы (ДНФ) представления логической функции.

Таким образом, сложение двоичных кодов сводится к вычислению функций (21 -22) для каждого разряда последовательно справа - налево.

На уровне операций двоичного сложения и вычитания кончается программная реализация алгоритма. Исполнение этих операций реализуется электронными схемами центрального процессора компьютера, которые исполняют роль аналоговой модели двоичного сложения и вычитания. По сути дела, конструируется электронная схема, являющаяся описанием логических функций (21-22) и вычисляющая их значения при заданных аргументах.

Процедуральная форма определения функции.


А как определить функцию - операцию умножения целых чисел? Табличное задание такой функции невозможно, так как такая таблица имела бы бесконечное число строк. В этом случае используется процедуральное задание функции.

Вместо таблицы функции умножения, предлагается алгоритм поразрядного умножения, который для каждой пары чисел позволяет определить правильный результат. (Поиск строки по заданному ключу заменяется анализом набора исходных данных, в результате чего получается правильный результат.) Таким же образом, процедурально, определяется функция деления. Для двоичных чисел имеются аналогичные алгоритмы, которые представляются в виде программы "встроенной" в центральный процессор.

Мы рассмотрели основные способы формального определения функционального преобразования данных: конечная таблица; записанные в аналитическом виде логическая и вещественная функции. Алгоритмы вычисления такого функционального преобразования предполагают существование исполнителя, способного выполнять следующие операции: сравнение, конъюнкция, дизъюнкция, отрицание, двоичное сложение и вычитание. Эти операции исполняются электронными схемами, которые, по сути дела, являются аналоговыми моделями вычисления соответствующих функций.

Исполнитель вычисляет значение функции при заданном аргументе, выполняя соответствующую программную запись алгоритма.

Универсальные и специальные алгоритмы.


Если алгоритм может быть применен для вычисления значений некоторого класса функциональных преобразований, то мы называем его универсальным алгоритмом. Очевидно, что перед исполнением универсального алгоритма необходимо "сообщить" ему описание конкретного функционального преобразования (Рис. 3.a). Примеры таких алгоритмов: вычисление значения функции заданной конечной таблицей - графиком; вычисление вещественной функции, представленной в аналитическом виде. В первом случае, в качестве описания функционального преобразования выступает таблица, во втором - арифметическое выражение.



Рис. 3. Универсальный и специальный алгоритмы

Алгоритм, применимый для вычисления значения только одного преобразования данных мы называем специальным алгоритмом (Рис. 3b). Примером является алгоритм умножения двух чисел. Он предназначен для вычисления значения конкретной бинарной функции умножения. Очевидно, что в этом случае описание функции "сообщать" алгоритму нет необходимости.

Более сложный пример специального алгоритма - компилятор с языка программирования Паскаль. Набор исходных данных d - символьный текст программы, набор результирующих данных r - программа в двоичных кодах. Очевидно, что существует функциональное отображение, вычисление значения которого F(d) = r составляет существо работы алгоритма компиляции.

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

К сожалению, многие прикладные задачи, которые необходимо решать, не могут быть представлены формально в виде функционального преобразования данных. Единственный выход - разрабатывать для их компьютерной реализации специальный алгоритм, анализируя и повторяя действия человека решающего эту задачу. В этом случае алгоритмист должен "изобрести" способ вычисления значения функционального преобразования, которое он представляет лишь интуитивно. Такие алгоритмы называют эвристическими. Отсюда возникает, к сожалению, очень распространенная ситуация: программная реализация алгоритма работает, но вычисляет не то (чаще, не совсем то) функциональное преобразование, которое подразумевалось. Здесь возникают серьезные проблемы надежности и тестирования программ, обсуждение которых выходит за рамки настоящего методического руководства.

Свойство массовости и результативности алгоритма.


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

Естественно, что эту проблему не имеет смысла решать для одного единственного набора исходных данных. Поэтому, для каждого алгоритма должна четко определяться область допустимых наборов данных, т.е. таких данных к которым применим этот алгоритм. (Очевидно, что эта область совпадает с областью определения функционального преобразования). Говорят, что алгоритм обладает свойством массовости, подразумевая под этим, что он правильно преобразует любой набор исходных данных из области допустимых.

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

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

Примечание. Безрезультативность алгоритма не следует путать с зацикливанием программы, которое может возникать в случае некорректной реализации результативного алгоритма. Более того, не следует успокаиваться, если программа кончает свою работу за конечное число шагов. Вполне возможно, что вместо решения системы алгебраических уравнений она вычисляет фазы луны во времена фараона Рамсеса II. (Смотри замечание выше по поводу тестирования и надежности программирования).

Язык блок - схем как язык записи алгоритмов.


Выше мы говорили, что для записи алгоритма используется язык блок - схем. Рассмотрим подробнее грамматику этого языка.

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

Элементы управляющих структур.





Обозначение обработки. Действие, которое необходимо выполнить, обозначается прямоугольником, в который входит и из которого выходит ровно одна линия управления. Этот прямоугольник называется узлом обработки, или функциональным узлом.

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

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

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




Начало алгоритма (вход в блок - схему) и конец алгоритма (выход их блок - схемы) изображаются очевидным образом.


Изображения любой из управляющих структур представляют собой комбинации этих обозначений.

Основные управляющие структуры.


Далее мы проанализируем специфику преобразования данных и выделим базисные классы преобразований. Для каждого из них предложим соответствующую управляющую структуру.

Безальтернативные вычисления
(управляющая структура "следование").


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

Ввод данных. Предписание на ввод данных содержит указание устройства ввода и имя переменной, значение которой надо ввести.

Чаще всего мы будем определять это действие в виде оператора ввода с клавиатуры:

Ввод(<список переменных>). (0)

Допускается неформальное описание ввода. Например: "читать очередную запись входного файла".

Изменение данных. Чаще всего предписание на изменение данных мы будем представлять в виде оператора присваивания (последовательности операторов присваивания). В языке программирования есть специфическое обозначение оператора присваивания:

<переменная> : = <арифметическое выражение> (0)

Допускается неформальное описание преобразования данных. Например: "Учесть сумму в строке баланса и в итоговой строке".



Вывод данных. Предписание на вывод данных содержит указание устройства вывода и имя переменной, значение которой следует вывести.

Чаще всего мы будем определять это действие в виде оператора вывода на монитор:

Вывод(<список переменных>). (0)

Допускается неформальное описание вывода. Например: "печатать результат вычислений".

Самая простая и очевидная управляющая структура - следование (Рис. 4). Допускается запись последовательности действий по преобразованию данных в одном прямоугольнике.



Рис. 4. Управляющая структура "следование".

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

Прикладная задача. Приложение: алгоритм 1 Вычисление площади треугольника. Для хранения размеров сторон треугольника используем переменные a,b,c. Преобразование данных задается двумя операторами присваивания:

(0)

Результат получается в переменной s. Переменная p используется для хранения промежуточного результата - полупериметра треугольника.

Альтернативные вычисления (управляющая структура "выбор").


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

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

Для реализации альтернативного двоичного выбора используется управляющая структура выбор в двух ее модификациях (Рис. 5). Условие р (логическая функция) принимает два значения: {True - да, False - нет }. Если структура выбора "полная", то в зависимости от значения условия выполняется либо действие S1, либо действие S2. Если структура выбора "укороченная", то в случае истинности условия выполняется действие S1. В противном случае его выполнение игнорируется.



Рис. 5. Полная и укороченная управляющая структура "выбор".

В языках программирования есть оператор, обозначающий эту управляющую структуру:

if p then S1 else S2 или if p then S1 (0)

Действием является либо простой оператор, либо составной оператор. Составной оператор - запись на языке программирования произвольной управляющей структуры, заключенная в операторные скобки.

Прикладная задача. Приложение: алгоритм 2. Напечатать наибольшее из двух заданных чисел.

Для хранения сравниваемых чисел отводим переменные a,b. Результат хранится в переменной Max..

Как уже говорилось, внутри блока действия может размещаться любая управляющая структура. Характерный пример, когда внутри блоков S1 и\или S2 размещается, в свою очередь, управляющая структура выбора.

Прикладная задача. Приложение: алгоритм 3. Напечатать наибольшее из трех заданных чисел.

Повторяющиеся вычисления (управляющая структура "цикл пока").


Большинство вычислительных процессов реализуются как длинные и очень длинные последовательности действий. Возникает проблема компактной записи длинной последовательности действия. К счастью, вычислительные процессы обладают замечательным свойством: в последовательности действий можно выделить подпоследовательности, в каждой из которых выполняются однородные действия. И эти подпоследовательности однородных действий можно обозначить управляющей конструкцией цикл.

Прикладная задача. Приложение: алгоритм 4. Вычисление вещественной функции в заданном интервале с заданным шагом. Представим предписание на вычисление этой функции в виде оператора присваивания:

z : = a*exp(b*x-c*x*x).

Пусть интервал вычисления (-1,1), шаг 0.5. Тогда вычисление выполняются в следующих точках: (-1, -0.5, 0, 0.5 ,1). Такое вычисление можно записать в виде последовательности пяти действий, каждое из которых состоит из оператора присваивания и оператора вывода. А если вычисления выполняются в тысяче точек: интервал вычислений (1,1000), шаг вычислений 1? А если сто тысяч точек? В этих случаях, теоретически рассуждая, можно представить алгоритм в виде управляющей структуры следования, состоящей из большого количества блоков. На практике это выглядит абсурдом. А в случае произвольного интервала вычислений, даже теоретически рассуждая, запись такой управляющей структуры не представляется возможной.

Управляющая структура цикл позволяет "свернуть" длинную последовательность действий и представить ее в компактном виде. Основным типом цикла является цикл пока (Рис. 6). Он предписывает выполнять тело цикла до тех пор ПОКА истинно условие p. В качестве такого условия выступает логическое выражение. Тело цикла - действие, как для управляющей структуры ВЫБОР.



Рис. 6. Управляющая структура "цикл пока".

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

В языках программирования есть оператор, обозначающий эту управляющую конструкцию:

while p do (0)

тело цикла

Использование "цикла пока" позволяет записать алгоритм вычисления функции в заданном интервале (x1,x2) с шагом dx (Приложение: алгоритм 4).

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

Доказано, что алгоритм решения любой прикладной задачи можно сконструировать только из структур следование, двоичный выбор и цикл ПОКА. В результате такого конструирования получается структурная блок - схема алгоритма.

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

Современные языки программирования являются также структурными, т.е. включают в себя операторы, обозначающие эти управляющие структуры - двухполюсники. Оператор (составной оператор) обозначает "узел обработки", линейный участок программы - "следование", оператор if - "выбор", оператор while - "цикл пока". Поэтому, запись структурной блок - схемы на современном языке программирования сводится, по сути дела, к перекодировке и не является проблемой.

Замечание. За структурность программы, как правило, приходится платить:

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

Вспомогательные управляющие структуры.


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

Повторяющиеся вычисления (управляющая структура "цикл for").


Прикладная задача. Приложение: алгоритм 5. Вычислить факториал для заданного n. Известно, что факториал вычисляется по следующей формуле:

(0)

Здесь используется характерная и часто встречающаяся комбинация управляющих конструкций, предписывающая выполнить тело цикла вполне определенное число раз (в данном случае n раз). Общий вид такой конструкции приведен на Рис. 7.a. Она предписывает выполнить тело цикла при следующих значениях параметра цикла i:

нач, нач+шаг, нач+2ґшаг,нач+3ґшаг...,конец.

Здесь, нач - переменная (константа) декларирующая начальное значение параметра цикла, конец - переменная (константа) декларирующая конечное значение параметра цикла, шаг- переменная (константа) декларирующая приращение параметра цикла


Рис. 7. Управляющая конструкция "цикл for"(a) и ее обозначение (b).

Такая управляющая конструкция получила специальное название "цикл for" или "цикл для". В языках программирования есть соответствующий оператор для записи подобной управляющей конструкции:

for i : = нач to конец step шаг do (0)

тело цикла

Приращение параметра цикла называется "шаг цикла". В некоторых языках шаг цикла произвольный, в других языках может иметь только значение "единица" и в операторе if не указывается. Имеется редко используемое, но удобное обозначение "цикла for" на языке блок - схем (Рис. 7.b).

Повторяющиеся вычисления (управляющая структура "цикл до").


Факториал существует только для положительного числа n. В алгоритме (Рис. 5) мы допускаем ввод числа n любого знака, т.е. не контролируем допустимость исходных данных. Для такого контроля целесообразно использовать еще один вид управляющей конструкции - "цикл до" (Рис. 8. Управляющая конструкция "цикл до". Она предписывает выполнять тело цикла до выполнения условия p. Также как и для "цикла пока", условие p является логическим выражением, включающим в себя параметр цикла. Последний должен изменяться в теле цикла таким образом, чтобы условие p в конечном итоге стало истинным.

Рис. 8. Управляющая конструкция "цикл до"

В языках программирования есть специальный оператор, обозначающий эту управляющую конструкцию:

repeat (0)

тело цикла

until p

Замечание. Если тело "цикла пока" может не выполняться ни одного раза, то тело "цикла до" выполняется хотя бы один раз.

Альтернативные вычисления (управляющая структура "множественный выбор").




Рис. 9. Алгоритмизация обработки многозначного условия вложенными конструкциями двоичного выбора.

Основная управляющая структура "выбор" включает в себя условие p, которое имеет два возможных значения: {True, False}. Однако при разработке алгоритмов возникают ситуации, когда условие p имеет k значений.

Конечно, алгоритмизировать обработку такого многозначного условия можно посредством вложенных конструкций выбора (Рис. 9).

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

Можно предложить алгоритмизацию обработки многозначного условия без вложенности конструкций выбора. Плата за такую простоту - большее время обработки условия.



Рис. 10. Алгоритмизация обработки множественного условия следующими друг за другом конструкциями укороченного двоичного выбора.

Для удобства алгоритмизации обработки множественного выбора используется специальное обозначение - вспомогательная управляющая конструкция "множественный выбор" (Рис. 11).



Рис. 11. Вспомогательная управляющая конструкция "множественный выбор".

Замечание. Допускается объединение нескольких значений в группы для реализации одной и той же обработки.

В языках программирования есть специальный оператор, обозначающий эту управляющую конструкцию:

case p of (0)

группа значений1: обработка1;

группа значений2: обработка2;

группа значений3: обработка3;

...

else обработка недопустимого. варианта

end

Обработка последовательности данных без запоминания.


Последовательностью называется функция, однозначно отображающая множество натуральных чисел N на множество X произвольной природы:

P: N®X. (0)

Табличная форма определения такой функции имеет следующий вид:

n

1

2

3

4

5

6

7

...

n

P(n)

X1

X2

X3

X4

X5

X6

X7

...

Xn

В силу того, что область определения последовательности - функции всегда одинакова, принято задавать последовательность в форме образа функции P(n):

P(n) = X1,X2,X3,X4,X5,X6,X7,...,Xn. (0)

При этом об элементах образа функции говорят как об элементах последовательности. Число n называется длиной последовательности.

Отметим основные свойства последовательности:

При решении многих прикладных задач набор данных представляется в виде последовательности данных.

В зависимости от допустимости изменения числа элементов в процессе обработки, назовем три разновидности последовательности данных.

изменение к-ва элементов®

тип последовательностиЇ

перед обработкой

в процессе обработки

Фиксированная

нет

нет

Статическая

да

нет

Динамическая

нет

да

Динамическая

да

да

Замечание. Фиксированную последовательность, элементами которой служат числа, принято также называть вектором. Длина вектора определяется на этапе постановки прикладной задачи.

Обработка фиксированной последовательности данных.


Прикладная задача. Приложение: алгоритм 6. Определить среднюю температуру Mid за сутки, если известна последовательность T1,...,T24 измерений температуры в начале каждого часа суток.

Эта характерная задача обработки последовательности, которая включает в себя определение суммы S всех элементов последовательности. Переменную S мы будем называть "накапливающей переменной". Такая переменная используется в теле цикла, в операторе присваивания: S : = S + T, где она последовательно суммирует значения T1,...,T24 всех элементов последовательности. Присваивание n : = 24 позволяет реализовать цикл for с фиксированным числом оборотов.

Обработка статической последовательности данных известной длины.


Прикладная задача. Приложение: алгоритм 7. Разработать алгоритм для определения среднего дохода сотрудников любого учреждения. Число сотрудников каждого учреждения известно - предоставляется список: D1,D2,...,Dn, зарплат сотрудников каждого учреждения.

Вместо присваивания переменной n фиксированного значения оператором присваивания, осуществляется ввод с контролем в переменную n числа сотрудников данного учреждения. Таким образом, имеется возможность при каждом запуске программы устанавливать необходимое число оборотов цикла for. В теле цикла используется накапливающая переменная S. Результат получается в переменной Mid.

Обработка статической последовательности данных неизвестной длины.


Далеко не всегда длина обрабатываемой последовательности известна априори. Определять эту длину либо нецелесообразно, либо не представляется возможным.

Прикладная задача. Приложение: алгоритм 8. При каждом сеансе связи, искусственный спутник "сбрасывает" на Землю последовательность ежеминутных измерений температур. Время сеанса зависит от траектории движения спутника и является переменной величиной. Следовательно, длина последовательностей температур различна для каждого сеанса связи и заранее неизвестна. Необходимо разработать алгоритм, определяющий минимальную и максимальную температуру за время сеанса связи.

Здесь целесообразно использовать признак конца последовательности - число, которое не может появиться при измерениях. Предполагается, что спутник заканчивает последовательность сбрасываемых данных этим признаком. Для хранения значения этого признака вводится переменная Finish.

Используем переменные Max и Min для хранения максимальной и минимальной температуры. Устанавливаем для этих переменных начальные значения, которые также не могут встречаться в последовательности температур. Причем, для максимума устанавливаем очень маленькое значение, а для минимума - очень большое.

Здесь нет возможности использовать цикл for, т.к. число элементов обрабатываемой последовательности, которое определяет число оборотов цикла, априори неизвестно. Используем "цикл пока", который повторяется до тех пор, пока элемент последовательности температур не равен признаку конца. Такая организация цикла требует ввода первого элемента последовательности перед началом цикла. При каждом обороте цикла корректируется максимальное (минимальное) значение двух переменных: Max и Min.

Обработка последовательности данных с запоминанием.


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

Хранение последовательности.


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

Проще всего обстоит дело с хранением фиксированной последовательности длины Size. Для этого декларируют массив нужного типа и нужной размерности:
<тип> имя массива[
Size]. Для хранения статической последовательности, волевым решением, устанавливают максимально допустимую длину обрабатываемой последовательности Size и декларируют массив такой же размерности. При хранении допустимой последовательности длины n< = Size используется только часть массива (Рис. 12.a). Поэтому, следует различать: размерность массива хранения (которая запоминается в простой переменной Size) и длину хранящейся в массиве последовательности (которая запоминается в простой переменной n). Последовательность, хранящуюся в массиве, часто называют массивом данных. Поэтому, следует также различать: массив хранения и массив данных, хранящийся в массиве хранения.



Рис. 12. Хранение статической последовательности в одномерном однородном массиве.

Замечание. В случае, когда тип элементов массива численный, целесообразно хранить размерность массива хранения и длину последовательности в первых двух строках массива хранения (Рис. 12.b). В этом случае, первый элемент последовательности располагается в третьей строке массива хранения.

Ввод последовательности известной длины в массив хранения Mas и вывод последовательности из массива хранения Mas показаны в Приложении: алгоритм 9. При этом требуется ввод длины последовательности в переменную n. В силу априорного знания длины последовательности, возможно использование цикла for.

Запись алгоритма в расчете на реализацию логической функцией.


Определенные алгоритмы целесообразно разрабатывать в расчете на их запись в языке программирования как подпрограмм - функций логического типа. Это позволяет в процессе выполнения подпрограммы определить удачу - неудачу предписанных действий (значение функции) и получить результирующие значения необходимых переменных (побочный эффект подпрограммы - функции).

В языке программирования Паскаль заголовок логической подпрограммы - функции выглядит следующим образом:

function <имя функции>(L1;L2):logical. (0)

Здесь, L1 - список входных переменных - аргументов, L2 - список результирующих переменных.

В языке программирования Си нет логического типа функции. Такая функция реализуется функцией, которая имеет целочисленный тип:

int <имя функции>(L,L2). (0)

Предполагается, что значение функции 0 обозначает логическую константу False, тогда как значение функции 1 обозначает логическую константу True. Для возврата значения используется специфический оператор return. Как и в случае языка Паскаль, используется "побочный эффект" для выдачи значения результирующих переменных.

Обобщая стандарты языка Паскаль и языка Си, мы будем для определения значения функции использовать оператор return(T), когда значение функции надо сделать истинным, или оператор return(F), когда значение функции надо сделать ложным.

Прикладная задача. Приложение: алгоритм 10. Ввод последовательности неизвестной длины в массив хранения. Используется признак конца последовательности Finish. Подпрограмма - функция Input выдает логическое значение T (1) если последовательность "убралась" в массив хранения и выдает значение F (0) в противном случае (переполнение массива). Это позволяет, после исполнения функции ввода, проанализировать ее значение и определить, убралась ли последовательность в массив или произошло его переполнение. Существенно, что в данном случае используется так называемый, "побочный эффект", когда подпрограмма - функция в качестве результата не только выдает то или иное значение, но также изменяет один или несколько фактических параметров. В данном случае, в качестве "побочного эффекта" выдается значение выходной переменной - массив хранения М, и длина введенной в этот массив последовательности, в виде значения выходной переменной n.

Все алгоритмы раздела 3 можно реализовать, предварительно запоминая последовательность в массиве хранения.

Прикладная задача. Приложение: алгоритм 11. Модификация алгоритма вычисления минимакса для последовательности, хранящейся в массиве М. Число n элементов последовательности становится определенным после ввода ее в массив. Следовательно, просмотр элементов последовательности можно реализовать посредством цикла for. В этом случае, в качестве начальных значений переменных Max и Min используется первый элемент последовательности и просмотр последовательности начинается со второго элемента.

Кроме того, определяются не только минимальное и максимальное значение элементов последовательности, но также порядковый номер (индекс) этих элементов (переменные IndMin и IndMax).

Поиск элемента последовательности по ключу.


Прикладная задача. Приложение: алгоритм 12. В прикладном программировании часто встречается необходимость определить: является ли заданный объект (ключ) элементом последовательности. И, в случае положительного ответа на этот вопрос, требуется определить порядковый номер - индекс этого элемента. Подобную процедуру принято называть "поиском по ключу".

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

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

Идея его чрезвычайно проста. На каждом шаге поиска делим последовательность пополам: Pi = (Pўi,Pўўi). Линейная упорядоченность последовательности позволяет простой операцией сравнения определить в какой из половин может находиться элемент последовательности равный ключу. Пусть это подпоследовательность Pi+1 = Pўi . Она, в свою очередь, делится пополам: Pi+1 = (Pўi+1,Pўўi+1). И снова определяется подпоследовательность, в которой может находиться элемент равный ключу. Процесс деления пополам повторяется до тех пор, пока либо не наткнемся на элемент равный ключу (удача поиска) либо дальнейшее деление станет невозможным (неудача поиска).



Рис. 13. Принятие решения при поиске делением пополам

Принятие решения о том, с какой подпоследовательностью работать на шаге n+1 отражено на Рис. 13.

Введем переменные - указатели элементов подпоследовательности в массиве хранения Mas: первый - первый элемент подпоследовательности Pi; последний - последний элемент подпоследовательности Pi; текущий - текущий элемент, указывающий середину подпоследовательности Pi.

Сортировка последовательности длины n.


Прикладная задача. Приложение: алгоритм 14. Как явствует из предыдущего раздела, поиск в линейно - упорядоченной последовательности более эффективен, чем в неупорядоченной последовательности. Линейно - упорядоченную последовательность принято называть отсортированной последовательностью (отсортированным массивом данных). Возможность сортировки последовательности предполагает, что для всех ее элементов определено отношение линейного порядка, т.е. для любых двух элементов можно однозначно определить, какой элемент предшествует какому элементу.

Назовем два наиболее важных отношения линейного порядка:

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

В каждый момент времени хранящаяся в массиве Mas последовательность P разбивается на две подпоследовательности:

Переменная First - указатель первого элемента еще не отсортированной части последовательности.

Переменная Current - указатель текущего просматриваемого элемента еще не отсортированной части последовательности.



Алгоритм сортировки

  1. Указатель First устанавливается на первый элемент массива хранения (отсортированной части последовательности еще нет).

  2. Повторяются пункты 3-5 пока Firstn-1.

  3. Просматривая несортированную часть последовательности (массив хранения от First до n), определяем указатель Min минимального элемента.

  4. Меняются местами первый элемент несортированной части последовательности и минимальный элемент несортированной части последовательности.

  5. Первый элемент несортированной части последовательности становится последним элементом сортированной части последовательности. (Указатель First увеличивается на единицу).

Пример.




¬значение First®

номер строкиЇ

1

2

3

4

5

6

7

8

9







1

3

1

1

1

1

1

1

1

1

1

1

2

4

4

2

2

2

2

2

2

2

2

2

3

1

3

3

3

3

3

3

3

3

3

3

4

9

9

9

9

4

4

4

4

4

4

4

5

8

8

8

8

8

5

5

5

5

5

5

6

2

2

4

4

9

9

6

6

6

6

6

7

10

10

10

10

10

10

10

7

7

7

7

8

7

7

7

7

7

7

7

10

8

8

8

9

6

6

6

6

6

6

9

9

9

9

9

10

5

5

5

5

8

8

8

8

10

10

10




3

6

3

6

10

9

8

10

9










¬указатель минимального элемента®








Примечание. В некоторых случаях первый элемент несортированной части последовательности является минимальным. В этом случае, первый элемент несортированной части последовательности меняется сам с собой.

Приложение. Блок - схемы алгоритмов





Алгоритм 1. Вычисление площади треугольника



Алгоритм 2. Печать наибольшего из двух чисел




Алгоритм 3. Печать наибольшего из трех чисел




Алгоритм 4. Вычисление графика функции в заданном интервале


Алгоритм 5. Вычисление факториала


Алгоритм 6. Обработка фиксированной последовательности данных


Алгоритм 7. Обработка статической последовательности данных известной длины




Алгоритм 8. Вычисление минимакса



Алгоритм 9. Ввод в массив Mas и вывод из массива Mas статической последовательности известной длины



Алгоритм 10. Ввод в массив Mas статической последовательности неизвестной длины



Алгоритм 11. Вычисление минимакса для последовательности хранящейся в массиве М


Алгоритм 12. Поиск в несортированном массиве Mas


Алгоритм 13. Поиск делением пополам в сортированном массиве Mas


Алгоритм 14. Сортировка элементов последовательности

Содержание





Учебный материал
© nashaucheba.ru
При копировании укажите ссылку.
обратиться к администрации