Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Демидов Основы программирования в примерах на языке ПАСЦАЛ 2010

.pdf
Скачиваний:
128
Добавлен:
16.08.2013
Размер:
1.28 Mб
Скачать

writeln('no solution');

end.

d = b2-4ac

Да

Нет

D >= 0 ?

x1 = (-b + √d)/2a

x2 = (-b - √d)/2a

Вывести x1 и x2

Вывести «Корней нет»

Рис. 2. Блок-схема алгоритма вычисления корней квадратного уравнения

Оператор ветвления case

Ещё один оператор ветвления case of используется в тех случаях, когда существует несколько альтернативных ветвей. Например, стоит задача получить название месяца по его порядковому номеру в году. Функция, которая это делает, может выглядеть следующим образом:

function GetMonthName(MonthNumber: integer): string; begin

case MonthNumber of

1:GetMonthName := 'Gennaio';

2:GetMonthName := 'Febbraio';

3:GetMonthName := 'Marzo';

41

4:GetMonthName := 'Aprile';

5:GetMonthName := 'Maggio';

6:GetMonthName := 'Giugno';

7:GetMonthName := 'Luglo';

8:GetMonthName := 'Agosto';

9:GetMonthName := 'Settembre';

10:GetMonthName := 'Ottobre';

11:GetMonthName := 'Novembre';

12:GetMonthName := 'Dicembre';

else

GetMonthName := ''; end;

end;

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

Конечно, эту задачу можно решить и с помощью оператора if, но тогда понадобится 12 вложенных операторов if вместо одного case. Кроме того, скорость работы оператора case будет гораздо выше:

function GetMonthName(MonthNumber: integer): string; begin

if MonthNumber = 1 then GetMonthName := 'Gennaio';

else if MonthNumber = 2 then GetMonthName := 'Febbraio'; else if MonthNumber = 3 then

else

GetMonthName := ''; end;

end;

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

function GetSeason(MonthNumber: integer): string; begin

case MonthNumber of

1,2,12: GetSeason:= 'L''inverno';

42

3..5: GetSeason:= 'La primavera'; 6..8: GetSeason:= 'L''estate'; 9..11: GetSeason:= 'L''autunno'; else

GetMonthName := ''; end;

end;

Здесь указываются несколько вариантов либо с помощью перечисления через запятую, либо с помощью диапазона значений (интервала). Допускается указывать несколько интервалов через запятую.

NB! Одинарная кавычка внутри строки удваивается. Операционная семантика оператора ветвления case:

1)найти значение аргумента оператора среди вариантов;

2)если найден вариант, включающий искомое значение, то выполнить оператор в соответствующей ветви. Если вариант не найден и предусмотрена альтернативная ветвь

(после else), то выполнить оператор в альтернативной ветви.

Ветвление с помощью оператора case графически изображено на рис. 3.

Аргумент-переменная

Подмножество

Подмножество

Иначе

значений 1

 

значений N

 

 

 

 

 

Ветвь 1

Ветвь N

 

Ветвь N+1

 

 

 

 

 

Рис. 3. Блок-схема исполнения оператора case

43

Замечания:

значения в альтернативах не должны повторяться или пересекаться между собой – это гарантирует единственность выбора альтернативы;

при описании альтернативы можно использовать только константные значения и их комбинации;

если нужно указать несколько операторов в одной ветви, то необходимо использовать составной оператор begin … end после двоеточия:

case <var> of

<value1>: begin

end; <value2>:

end;

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

– более медленным линейным.

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

дополнительный переход на альтернативную ветвь.

Выражения и операции

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

В нотации РБНФ3 выражение можно определить следующим образом:

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

44

выражение =

переменная | константа | вызов_функции | (выражение) | унарная_операция выражение | выражение бинарная_операция выражение

вызов_функции =

имя_функции "(" [ выражение {"," выражение}] ")"

Здесь знак «|» означает выбор, квадратными скобками обрамляют необязательные конструкции, фигурными – повторение конструкции 0 и более раз, в кавычки помещают символы языка.

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

5 8.92 pi arr[i] a_phone_rec.fio

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

Любое выражение, поставленное в скобки, также является выражением.

Перед выражением может стоять унарная операция (например, «-» или not).

Бинарные операции записываются в инфиксной форме, т.е. знак операции стоит между операндами-выражениями. Примеры:

(a or b) and (not a or not b) and true (arr[i] + arr[j])*sin(alpha)

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

45

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

Операции делят на несколько групп:

арифметические (+, -, *, /, div, mod);

логические (and, or, not, xor);

битовые (shl, shr, and, or, not, xor);

сравнения (=, <>, <, >, >=, <=);

строковая операция конкатенации (+);

операция взятия адреса значения переменной @.

Тип всего выражения можно определить по используемым операциям и типу аргументов операций. Компилятор следит за тем, чтобы операция была допустима для типов аргументов. Например, аргументы операций div и mod могут быть только целочисленных типов, причём результат неизбежно имеет целочисленный тип. Операции сравнения допустимы для многих типов аргументов, но компилятор отследит, чтобы типы были одинаковы или совместимы. Результат операций сравнения неизбежно имеет логический тип, независимо от типов аргументов.

Задания для самостоятельного выполнения

1. Применение сложных выражений внутри if, применение case. Написать программу, определяющую существование треуголь-

ника по трём сторонам:

var

side1, side2, side3: integer; exist: Boolean;

begin

writeln('Enter 3 sides:'); readln(side1); readln(side2); readln(side3);

exist := (side1 + side2 > side3) and (side2 + side3 > side1) and (side1 + side3 > side2);

if exist then writeln('Triangle exists') else writeln('Triangle does not exist');

end.

2. Написать программу, производящую над двумя вводимыми операндами указанную операцию ( +, -, *, /). Обратите внимание на потенциальное деление на ноль:

46

var

num1, num2: integer; op: char;

begin

writeln('Enter 2 numbers:'); readln(num1); readln(num2); writeln('Еnter operation: '); read(op);

case op of

‘+’: writeln(num1 + num2); ‘-’: writeln(num1 - num2); ‘*’: writeln(num1 * num2);

‘/’: if num2 = 0 then writeln ('Division by zero!') else writeln(num1/num2);

else writeln('Unknown operation!'); end;

end.

3. Для произвольной точки (x, y) вычислить выражение U в зависимости от принадлежности области D:

 

2

y

2

if x,y D;

 

1 x

 

U

 

 

 

if x,y D,

1 x 2 1 y 2

 

 

 

 

 

где D – заштрихованная область.

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

Один из вариантов программы выглядит следующим образом:

var x,y,u: real; begin

writeln('Enter 2 numbers:'); readln(x); readln(y);

if (x*x + y*y < 1)and ((y> x)and(x>0) or (y< x)and(x<0)) or (x*x + y*y > 1)and ((y>-x)and(x<0) or (y<-x)and(x>0)) then u := sqrt(1+x*x*y*y);

else u := sqr(1+x)*sqr(1+y); end.

47

Глава 5. Сортировка и поиск

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

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

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

критерий сравнения существует и известен (доступность);

объекты допускают сравнение по этому критерию (применимость);

результат сравнения двух объектов однозначен (различимость объектов).

Применение критерия можно реализовать с помощью операций сравнения над двумя объектами, а принятие решений после сравнения – с помощью оператора ветвления.

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

Рассмотрим возможную схему сортировки по возрастанию множества кубиков с числами, записанную на псевдокоде:

1.Найти кубик с минимальным числом

2.Поместить найденный кубик в начало ряда

3.Если ещё остались кубики,

48

то

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

иначе завершить работу 4. Повторить шаг 3.

Здесь подразумевается, что исполнитель умеет искать кубик с минимальным числом. Однако задача поиска ещё не решалась, поэтому рассмотрим возможную схему поиска, записанную на псевдокоде:

1.Взять первый попавшийся кубик

2.Если ещё остались кубики,

то

взять кубик среди оставшихся кубиков, сравнить числа на взятых кубиках, кубик с большим значением отложить в сторону

иначе завершить работу

3.Повторить шаг 2.

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

Если бы программа писалась на языке ассемблера, то переход к началу цикла представлял бы собой инструкцию безусловного или условного перехода jmp, je, jg и др. – от англ. jump (прыжок). Однако в языках третьего поколения имеются операторы цикла, которые объединяют в себе проверку условия повторения, тело цикла (что повторять) и переход на новый виток цикла. При этом структура программы становится прозрачной и простой.

Таким образом, операторы циклы вполне применимы для решения задач сортировки и поиска.

Операторы цикла

Вводятся три оператора для разных видов циклов:

с предусловием;

с постусловием;

с параметром.

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

49

параметром тело цикла выполняется столько раз, сколько указано в параметре цикла.

Оператор цикла while

Оператор предназначен для описания циклов с предусловием, записывается с помощью ключевых слов while и do и читается так: «Пока истинно <условие> выполнять <инструкции>».

Если требуется указать несколько инструкций в теле цикла, то следует использовать составной оператор begin…end:

while loop_condition do begin

end;

Операционная семантика оператора while:

1)вычисление значения предусловия;

2)если полученное значение истинно, то выполнить оператор в теле цикла, иначе завершить выполнение цикла (перейти к оператору, следующему за оператором цикла);

3)перейти на шаг 1.

Оператор цикла repeat

Оператор предназначен для описания циклов с постусловием, записывается с помощью ключевых слов repeat и until и читается так: «Выполнять <инструкции> до тех пор, пока <условие> не станет истинным».

repeat

until exit_condition;

Операционная семантика оператора цикла repeat:

1)выполнить операторы в теле цикла;

2)вычислить значение постусловия;

3)если полученное значение ложно (!), то перейти на

шаг 1, иначе завершить выполнение цикла (перейти к оператору, следующему за оператором цикла).

Нужно отметить, что условие в цикле repeat имеет обратный смысл, по сравнению с условием цикла while: для цикла repeat сле-

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]