ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ Федеральное государственное образовательное учреждение высшего профессионального образования «ЮЖНЫЙ ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ»
Е.С.НЕВСКАЯ, А.А.ЧЕКУЛАЕВА
ТЕХНОЛОГИЯ ВЫПОЛНЕНИЯ ИНДИВИДУАЛЬНЫХ ЗАДАНИЙ ЧАСТЬ 1
МЕТОДИЧЕСКИЕ УКАЗАНИЯ по курсу
«ИНФОРМАТИКА» для студентов 1 курса дневного и вечернего отделений факультета математики, механики и компьютерных наук
Ростов-на-Дону 2008
Методические указания разработаны сотрудниками кафедры прикладной математики и программирования старшим преподавателем Е.С. Невской и старшим преподавателем А.А. Чекулаевой.
Печатается в соответствии с решением кафедры прикладной математики и программирования факультета математики, механики и компьютерных наук ЮФУ, протокол № 10 от 24 июня 2008 г.
2
СОДЕРЖАНИЕ
Введение....................................................................................................... 4 1 Методология программирования............................................................ 5 2 Стиль программирования ........................................................................ 7 3 Некоторые приемы программирования.................................................. 9 4 Примеры выполнения заданий в первом семестре.............................. 11 4.1 Обработка чисел и последовательностей ....................................... 11 4.2 Табулирование функций .................................................................. 15 4.3 Ряды и пределы................................................................................. 18 4.4 Одномерный массив......................................................................... 25 4.5 Двумерный массив .......................................................................... 34 Литература ................................................................................................. 41
3
ВВЕДЕНИЕ Студенты первого и второго курсов слушают лекции по дисциплинам «Информатика» и « Языки программирования», подкрепляют изучение лекционных курсов на практических и лабораторных занятиях. Методические указания содержат рекомендации для выполнения индивидуальных заданий по программированию. Студент по каждому индивидуальному заданию должен представить отчет, соблюдая установившиеся требования. Отчет должен включать следующие пункты: 1) формулировка условия задачи; 2) постановка задачи; 3) метод решения; 4) описание алгоритма; 5) проверка правильности алгоритма; 6) программа на алгоритмическом языке; 7) тестирование программы для различных наборов входных данных; 8) выполнение программы и анализ результатов. В конкретных заданиях правила могут изменяться и детализироваться. Так, для простых задач пункты формулировка условия задачи и постановка задачи, а также пункты метод решения и описание алгоритма могут быть объединены. В первом семестре студенты выполняют индивидуальные задания по темам: работа с числами, ряды, обработка последовательностей, табулирование функций, работа с одномерным массивом и работа с двумерным массивом. Во втором семестре темы индивидуальных заданий следующие: использование процедурного типа в процедурах и функциях, обработка строк, работа с записями и массивами записей, текстовые и типизированные файлы, использование модульного подхода. Методические указания состоят из двух частей. В первую часть включены задания, выполняемые в первом семестре, а во вторую часть – задания, выполняемые во втором семестре.
4
1 МЕТОДОЛОГИЯ ПРОГРАММИРОВАНИЯ Методология программирования включает следующие компоненты − это наука, техника (ремесло) и искусство. На этапе проектирования программирование требует от программиста немалой изобретательности. Проект программы − это практически изобретение, произведение искусства. Но программирование − это одновременно и техническая задача, для решения которой формулируются технологические правила, представляющие собой эмпирически найденные правила хорошего программирования. Эти правила передаются от мастера к ученикам. Однако программирование − это наука. Наука показывает, как можно достичь множества целей, применяя строго определенные правила построения к основным конструктивным элементам. Наука демонстрирует, какие свойства программы выводимы из свойств, подразумеваемых у ее составляющих. Необходимость и возможность создания математической теории программирования были провозглашены в первые годы развития вычислительных машин. Это объясняется отчасти тем, что первыми программистами были математики и среди них − видные ученые. Математическая теория начала использоваться в таких разделах программирования, как языки и трансляторы, операционные системы и базы данных, далее проникла в исследования готовых программ и затронула сущность процесса программирования. Процесс подготовки задачи к решению на вычислительной машине условно включает следующие этапы: – математическая формулировка задачи; – выбор метода решения задачи; – разработка алгоритма; – описание алгоритма на алгоритмическом языке (получение программы); – тестирование программы; 5
– проведение расчетов, анализ результатов. Первый этап состоит в анализе проблемы и в построении математической модели, или в точной постановке задачи. На основе выделенных закономерностей, характеризующих моделируемое явление, уточняются входные и выходные данные и связи между ними. Таким образом, на этапе математической формулировки задача описывается в виде некоторой математической конструкции. Второй этап состоит в решении поставленной математической задачи. Математическую модель уже можно изучать чисто математическими методами, не вдаваясь в физическую природу объекта. Другими словами, необходимо выбрать метод решения задачи, с помощью которого разработать алгоритм ее решения (третий этап). Далее следует представить алгоритм в таком виде, чтобы вычислительная машина могла его выполнить (четвертый этап). Для этого нужно разбить алгоритм на элементарные операции, которые умеет выполнять машина, и записать каждую такую операцию на языке, понятном этой машине, т.е. представить алгоритм в виде программы. Как следует из анализа приведенных этапов, основная работа выполняется человеком без использования вычислительной машины. Фундаментальные идеи, лежащие в основе конструирования алгоритмов (в конечном итоге программ), можно объяснить и понять, не упоминая при этом вычислительную машину. Перечисленные этапы определяют процесс программирования. Программирование – дисциплина многоплановая; оно содержит множество нетривиальных проблем, требующих теоретического фундамента и систематического подхода. Интересные исследования и сложные проблемы возникают тогда, когда программы достигают определенной сложности и больших размеров.
6
2 СТИЛЬ ПРОГРАММИРОВАНИЯ Большое значение для успешной отладки программы имеют простота и рациональность ее кодирования. Когда программа написана аккуратно и логично, легче избежать ошибок или выявить их в случае возникновения. Простота программирования зависит от стиля программирования. Под стилем будем подразумевать набор приемов или методов программирования, которые используют опытные программисты, чтобы получить правильные, эффективные, удобные для применения и легко читаемые программы. Легко читаемая программа создает впечатление, что ее автор хорошо знал, что делал. Программа должна передавать логику и структуру алгоритма настолько, насколько это возможно. Правила хорошего стиля – это результат соглашения между опытными программистами. Следуя определенному стилю программирования, можно избежать многих трудностей, которые возникают при разработке и модификации программы. Приведем некоторые советы, которые являются результатом здравого смысла и опыта программистов. Пишите программы просто и четко (“Keep it simple!” – придерживайтесь простоты!), помните: программы читаются людьми. Если существует более одного способа сделать что-либо и выбор произвольный, остановитесь на одном способе и всегда его придерживайтесь. Делайте комментарии; комментарии должны содержать дополнительную информацию, а не перефразировать программу; каждая программа должна начинаться с комментария, описывающего цель программы (что делает программа). Делайте пробелы для улучшения читаемости программы. Размещайте пробелы с обеих сторон бинарной операции. Это выделяет операцию и улучшает читаемость программы. Используйте отступы для изображения структуры оператора. 7
Благодаря ступенчатой записи легко прослеживается структура алгоритма в программе. Операторы, принадлежащие одной и той же структурной конструкции, должны начинаться на одинаковом расстоянии от левого края. Этот же прием позволяет легко находить соответствующие друг другу открывающие и закрывающие скобки. Отступы в условных операторах и операторах цикла показывают состав оператора и упрощают чтение программы. Используйте имена с подходящей мнемоникой. Выбор осмысленных имен переменных помогают программе быть «самодокументируемой». Не используйте в качестве идентификаторов зарезервированные слова. В каждой строке программы должно быть не более одного оператора. Выбирайте представление данных, соответствующее задаче.
8
3 НЕКОТОРЫЕ ПРИЕМЫ ПРОГРАММИРОВАНИЯ Остановимся прежде всего на простых, часто встречающихся ошибках, к которым отнесем следующие: 1) отсутствие инициализации переменной; 2) отсутствие повторной инициализации переменной при повторном выполнении сегмента программы; 3) ошибки при расстановке скобок в выражениях; 4) попытка деления на ноль; 5) ожидание целого результата при делении целых чисел – деление двух целых чисел приводит к вещественному результату; 6) повторное использование параметра функции (процедуры) как локальной переменной внутри функции (процедуры) – синтаксическая ошибка; 7) извлечение квадратного корня из отрицательного числа; 8) использование вещественных значений в цикле while может привести к ошибке смещения количества повторений; 9) отсутствие круглых скобок в выражениях, включающих операции and и or, приводит к синтаксической ошибке; 10) индекс элемента массива не должен принимать значений вне диапазона допустимых значений индекса; 11) когда процедура (функция) содержит параметр, который она должна изменять, следует использовать передачу параметра по ссылке (параметрпеременная), иначе возникнет семантическая ошибка. Отсюда вытекают важные замечания, которые следует иметь в виду. Задавайте начальные значения всем счетчикам и переменным для накопления сумм и произведений. Обращайтесь к таблице старшинства операций при написании выражений, содержащих много операций. Убедитесь, что операции в выражении выполняются в ожидаемой последовательности. 9
В теле нерекурсивной функции используйте имя функции только в левой части оператора присваивания. Последний оператор печати должен перемещать курсор в начало новой строки. Это способствует возможности повторного использования программы. При выдаче вещественных значений используйте формат вывода вещественных чисел. Выполняйте тестирование программы. Тестирование представляет собой процесс выполнения программы для некоторого набора проверочных значений и сравнения полученных результатов с ожидаемыми. Успех тестирования заключается в выборе подходящего набора проверочных данных. Грамотно подобранный набор проверочных данных может в большей степени укрепить уверенность в том, что программа функционирует правильно. Необходимо проверять не только, делает ли программа то, для чего она предназначена, но и не делает ли она того, чего не должна делать. Тестирование это процесс исполнения программы с целью обнаружения ошибок. Необходимо досконально изучать результаты каждого теста. Тесты для неправильных и непредусмотренных входных данных следует разрабатывать так же тщательно, как для правильных и предусмотренных данных. Хорошим является тест, который имеет высокую вероятность обнаружения ещё не выявленной ошибки. Используйте так называемый прием
защитного программирования. Это
значит, что нужно составлять каждую программу так, чтобы она защищала саму себя от ошибок. Это, например, значит, что следует отслеживать неправильные данные, проверять на возможность арифметического переполнения, не извлекать корень квадратный из отрицательного числа. Каждая функция или процедура должна содержать одну, точно определённую операцию, а имя функции или процедуры должно отражать смысл данной операции. Это облегчает многократное использование этой операции. 10
4 ПРИМЕРЫ ВЫПОЛНЕНИЯ ЗА ДАНИЙ В ПЕРВОМ СЕМЕСТРЕ 4.1 Обработка чисел и последовательностей Задача 1 Даны длины сторон прямоугольника. Определить, на сколько квадратов можно разрезать прямоугольник, если каждый раз отрезать квадрат максимально возможной площади. Входные данные: a, b - длины сторон прямоугольника (переменные принадлежат классу натуральных чисел). Выходные данные: n – количество квадратов (переменная принадлежит классу натуральных чисел). Метод решения Метод решения задачи состоит в следующем: – выбрать большую сторону прямоугольника и определить, сколько раз в ней целиком поместится меньшая сторона (переменная k); – с остатком большей стороны и меньшей стороной повторить ту же операция (процесс завершается, когда остаток станет равным нулю). Графическая иллюстрация метода решения задачи представлена на рисунке.1.
Рисунок 1– Графическая иллюстрация алгоритма решения задачи.
11
Разработка алгоритма Алгоритм представляется в виде последовательности следующих действий: – определить a = max(a,b); – определить количество повторений меньшей стороны b на большей стороне a: k:=a div b; – определить остаток от деления a на b: a:=a mod b; – последовательность действий выполнить до условия a=0. Текст программы program Cycle; var a,b,k,c,n:
integer;
begin write('Введите стороны прямоугольника'); readln(a,b); n:=0; repeat if a
2) стороны прямоугольника: 7, 16 всего квадратов: 7 3) стороны прямоугольника: 7, 7 всего квадратов: 1 Задача 2 Дано натуральное число n и последовательность из n целых чисел. Найти среднее арифметическое положительных элементов последовательности, предшествующих первому нулевому элементу. Входные данные:
n – количество членов последовательности, x – очередной член последовательности.
Выходные данные: sr – среднее арифметическое положительных чисел. Промежуточные переменные: i – номер текущего элемента последовательности, s, k – сумма и количество положительных элементов последовательности до первого нуля, st – булевская переменная, указывающая на отсутствие или наличие нулевого элемента среди членов последовательности. Описание алгоритма Ввод элементов и их обработка выполняются в цикле для i от 1 до n. При каждом повторении цикла выполняется суммирование положительных элементов и подсчёт их количества, пока не встретится нулевой элемент (при этом переменная st сохраняет значение true). После ввода нулевого элемента, переменной st получает значение false и никаких действий по обработке не выполняется.
13
Решение задачи представлено программой Posledovat. program Posledovat; var x,i,n: integer; k: integer; { - количество положительных чисел} s: integer; { сумма положительных чисел} sr: real;{среднее арифметическое положительных чисел, расположенных до первого нуля в последовательности} st:boolean; begin write('Введите количество членов '); readln(n); s:=0; k:=0; st:=true; writeln('Вводите последовательность чисел'); for i:=1 to n do begin read(x); if st then if x>0 then begin s:=s+x; k:=k+1 end else if x=0 then
st:=false
end; if st then writeln('нет нуля')
14
else if k=0 then writeln('нет положительных элементов до нуля') else begin sr:=s/k; writeln('sr=',sr:10:3) end end. Тестовые примеры 1)
n = 5, {xn}= (-3 , 5 , 2 , 0 , 4), sr= 3.5
2)
n = 5, {xn}= (-3 , 5 , 2 , -2 , 5), нет нуля
3)
n = 5, {xn}= (-3 , -5 , 0 , 2 , 4), нет положительных элементов до нуля
4.2 Табулирование функций Задача 3 Выдать таблицу значений двух заданных вещественных функций от одной вещественной переменной f ( x) = tg ( x) и g ( x) = 1 /( x − 2 x ) . Постановка задачи Таблицу получить на заданном отрезке [a, b] с заданным шагом h. При построении таблицы проверять, определена ли табулируемая функция в
очередной точке таблицы. Если функция не определена, то в таблицу вместо значения функции помещать символ ‘- ‘ (прочерк). Входные данные: a, b – границы заданного отрезка, h – шаг таблицы. Выходные данные: таблица значений двух заданных функций. Вспомогательные переменные: x, y, z – переменны для значений аргумента и двух функций f и g. 15
Исследование поведения функций Функция f ( x ) = tg ( x) определена всюду, кроме тех значений x, в которых cos(x)=0. Функция
g ( x) = 1 /( x − 2 x )
не
определена,
если
x<0
или,
если
x − 2 x = 0 (если x 2 = 4 x ) т.е. при x=0 и x=4. Описание алгоритма Вычисления выполняются в цикле для x от a до b+h/2 с шагом h. На каждой итерации проверяется существование каждой в отдельности функции f(x) и g(x) . Если функция существует, то она вычисляется и её значение выводится. Если функция не существует, то функции не вычисляется, в этом случае выводится символ ‘–‘ (прочерк). Текст программы program Tablica; var a,b,h,x,y,z,eps:real; begin writeln('введите a,b,h,eps'); readln(a,b,h,eps); writeln('
x
y
x:=a; while x
-
')
16
z
');
else begin y:=sin(x)/cos(x); write(y:12:8) end; if(x<0)or (abs(x)<eps) or(abs(x-4)<eps) then writeln('
-
')
else begin z:=x-2*sqrt(x); writeln(z:12:8) end; x:=x+h end end. Тестовые примеры 1) a = -1.5707963,
b = 2,
h = 0.31415926,
Таблица результатов x -1.570796
y
z
-
-
-1.256637 -3.07768331
-
-0.942478 -1.37638187
-
-0.628319 -0.72654251
-
-0.314159 -0.32491969
-
0.000000 0.00000000
-
0.314159 0.32491969 -1.23940468 0.628319 0.72654251 -1.04491856 0.942478 1.37638187 -1.00085261 1.256637 3.07768331 -1.01485810 1.570796
-
-1.06856792
1.884956 -3.07768387 -1.16155065 17
eps = 0.0000001
Тестовый пример демонстрирует невозможность вычисления y при cos(x)=0 ( x= – π /2 и x= 2) a = – 0.5,
π /2 ) и невозможность вычисления z при x<0 и при x=0.
b = 4.5,
h = 0.5,
eps = 0.0000001
Таблица результатов x
y
z
-0.500000 -0.54630249
-
0.000000 0.00000000
-
0.500000 0.54630249 -1.09383632 1.000000 1.55740772 -1.00000000 1.500000 14.10141995 -1.05319726 2.000000 -2.18503986 -1.20710678 2.500000 -0.74702230 -1.50994071 3.000000 -0.14254654 -2.15470054 3.500000 0.37458564 -4.13808994 4.000000 1.15782128 4.500000 4.63733205
3.88561808
Второй тестовый пример демонстрирует невозможность вычисления z при x<0, при x=0 и при x=4. 4.3 Ряды и пределы Задача 4 Найти приближенное значение суммы сходящегося ряда
y =
∞
∑
n=0
a
n
n , общий член которого имеет вид a n = x / n! . Суммирование пре-
кратить, как только очередное слагаемое станет по абсолютной величине меньше eps (0< eps< 1),
18
x x2 x3 y = 1+ + + + ... 1! 2! 3! Входные данные:
x – значение, при котором вычисляется y, eps – константа для оценки величины члена ряда
Выходные данные:
y – приближённое значение суммы ряда.
Промежуточные переменные: an – очередной член ряда, n – целочисленная переменная обозначает номер очередного члена ряда. Метод решения Вычисление суммы y =
∞
∑
a
n =0
n
сходящегося ряда осуществляется на
основе рекуррентного соотношения:
⎧ y n = y n−1 + an , ⎨ y 0 = a0 ⎩
n = 1,2,...
Для получения рекуррентной зависимости, используемой при вычислении очередного члена ряда, находят отношение следующего члена ряда к предыдущему:
an x n ⋅ (n − 1)! x ⋅ 1 ⋅ 2 ⋅ ...(n − 1) x = = = , a n −1 1 ⋅ 2 ⋅ ... ⋅ n n n!⋅ x n −1 откуда ⎧ ⎨ a n = a n −1 ⋅ x / n , n=1,2,… , ⎩
a 0 =1, n=0.
19
Описание алгоритма В цикле на каждой итерации – проверяется абсолютная величина очередного члена ряда: |an| > eps, – если условие выполняется, то слагаемое прибавляется к сумме, определяется значение следующего члена ряда, и вычисления продолжаются, – если условие |an| > eps не выполняется, то завершается подсчёт суммы. Текст программы program Row1; var x, y, an, eps :real; n:integer; begin writeln('введите x и eps'); readln(x,eps); y:=0;
n:=0;
an:=1;
while abs(an)>eps do begin y:=y+an; n:=n+1; an:=an*x/n end; writeln('сумма=', y:12:7) end. Тестовые примеры 1) x = 1,
eps = 0.01,
y = 2.7083333
2) x = 1,
eps = 0.001,
y = 2.7180556
3) x = 1,
eps = 0.0001, y = 2.7182540
20
Вычисления при разных значениях eps позволяют получать более точные значения результата. Полученные значения можно сравнить с точным значением exp(1)=2.71828182845905. Задача 5 При заданном значении x, ε и а (а – не целое число) вычислить сумму s ( x, ε ) , прекратив вычисления, когда очередной член суммы (слагаемое) по абсолютной величине станет меньше ε . При том же значении x вычислить функцию y(x). Близость значений s ( x, ε ) и y(x) будет указывать на правильность вычислений.
1 x3 1⋅ 3 x5 1⋅ 3 ⋅ 5 x 7 x ⋅ + ...; ⋅ − s ( x, ε ) = − ⋅ + a 2 ⋅ 3 a3 2 ⋅ 4 ⋅ 5 a5 2 ⋅ 4 ⋅ 6 ⋅ 7 a7 ⎛x ⎞ x2 ⎟; [ x 2 < a 2 ] y ( x) = ln⎜ + + 1 . 2 ⎜a ⎟ a ⎝ ⎠ Входные данные: x,a – заданные значения для вычисления s(x, ε ), eps – константа для оценки величины очередного члена суммы. Выходные данные: s – приближённое значение суммы, y – значение функции y(x). Вспомогательные переменные: an – переменная для значения очередного слагаемого, с – переменная для значения x/a, b = с2 , n – обозначает номер очередного слагаемого. Метод решения Вывод рекуррентного соотношения для вычисления an:
(2n − 1)!!⋅x 2 n +1 ⋅ (−1) n an = , (2n)!!⋅(2n + 1) ⋅ a 2 n +1
∞
s ( x, ε ) = ∑ a n , n =0
21
an (2n − 1)!!⋅ x 2 n+1 ⋅ (−1) n (2n − 2)!!⋅(2n − 1) ⋅ a 2 n−1 = ⋅ = a n−1 (2n)!!⋅(2n + 1) ⋅ a 2 n+1 (2n − 3)!!⋅x 2 n−1 ⋅ (−1) n−1 2
x 2 ⋅ (2n − 1) ⋅ (2n − 1) x 2 ⋅ (2n − 1) , = (−1) ⋅ =− 2 a 2 ⋅ (2n + 1) ⋅ 2n a ⋅ (2n + 1) ⋅ 2n так как c=x/a, то
c 2 ⋅ (2n − 1) 2 . a n = −a n −1 ⋅ 2n ⋅ (2n + 1) Описание алгоритма Вначале проверяется условие x 2 ≥ a 2 . И если оно выполняется, выдаётся сообщение “неверный ввод” и программа завершает работу. При не выполнении условия x 2 ≥ a 2 , в цикле на каждой итерации – проверяется абсолютная величина очередного члена суммы ряда: |an| > eps. – если условие выполняется, то слагаемое прибавляется к сумме, определятся значение следующего члена ряда, и вычисления продолжаются. – если условие |an| > eps не выполняется, то завершается подсчёт суммы. Текст программы program Row2; var x, a, b, c, s, y, an, eps :real; n:integer; begin writeln('введите x,а и eps, так чтобы x*x
=a*a then begin writeln(' неверный ввод'); end; 22
exit
s:=0;
n:=0;
c:=x/a; b:=c*c;
an:=c;
while abs(an)>eps do begin s:=s+an; n:=n+1; an:=-an*b*sqr(2*n-1)/(2*n*(2*n+1)) end; writeln(' сумма=', s:12:7); y:=ln(c+sqrt(b+1)); writeln(' y=', y:12:7); end. Тестовые примеры 1) x = 5, a = 6, s = 0.7590636, 2) x = 5, a = 6, s = 0.7584857, 3) x = 5,
a = 10,
s = 0.4815104, 4) x = 10,
а = 5,
eps = 0.001 y = 0.7584861 eps = 0.000001 y = 0.7584861 eps = 0.001 y = 0.4812118 eps = 0.001
неверный ввод Задача 6 Найти приближенное значение предела последовательности { an } при n→∞, принимая за него такое значение an, при котором |an - an-1|<eps (0<eps<<1). Задана формула для вычисления предела последовательности
2 − a n3 an = и начальное приближение a 0 = 1 . 5 23
Входные данные: eps – константа для оценки величины разности двух соседних членов последовательности. Выходные данные: an
– приближённое значение предела последова-
тельности. Промежуточные переменные: ap – предыдущее значение предела последовательности. Описание алгоритма В цикле на каждой итерации – запоминается найденное очередное приближённое значение предела, – вычисляется следующее приближённое значение предела, – проверяется абсолютная величина разности этих двух приближённых значений предела. – если разность меньше заданного eps, то вычисления завершаются, иначе вычисления в цикле продолжаются. Текст программы program Lim; var an, ap, eps : real; begin writeln('введите
eps');
readln(eps); an:=1; repeat ap:=an; {запомнить предыдущее значение} an:=(2-an*an*an)/5 {вычислить следующее значение} until abs(an-ap) < eps; writeln(' предел равен', an:10:7) end. 24
Тестовые примеры 1) eps = 0.1,
предел равен 0.3873530
2) eps = 0.01,
предел равен 0.3883761
3) eps = 0.001,
предел равен 0.3882838
4) eps = 0.0001,
предел равен 0.3882838
5) eps = 0.00001,
предел равен 0.3882921
6) eps = 0.000001, предел равен 0.3882914 Из тестовых примеров видно, что при уменьшении eps находится более точное значение предела. 4.4 Одномерный массив Задача 7 Даны натуральное число n, массив из n вещественных чисел. Определить, сколько положительных элементов располагается между максимальным и минимальным элементами массива. Входные данные:
n – размер массива, а – массив вещественных чисел.
Выходные данные:
k – количество положительных элементов, распо-
ложенных между максимальным и минимальным элементами массива. Описание алгоритма – определить индексы максимального и минимального элементов, – определить границы просмотра массива для поиска количества положительных элементов между максимальным и минимальным элементами, – определить количество положительных элементов в найденном диапазоне. Используются следующие подпрограммы: – MinMax – процедура нахождения индексов максимального и минимального элементов массива из n элементов, 25
– Count – функция нахождения количества положительных элементов в диапазоне индексов [kmin, kmax] заданного массива. Текст программы program Vect_1; const nmax = 10; type
T_El= real; vect = array[1..nmax] of T_El;
var
a : vect;
n,i,kmin,kmax,k : integer; procedure MinMax(n: integer; const a: vect; var kmin, kmax: integer); var i:integer; begin kmin:=1; kmax:=1; for i:=2 to n do begin if a[i]a[kmax] then kmax:=i end end; function Count (kmin,kmax: integer; const a: vect):integer; var i,k:integer; begin k:=0;
26
for i:=kmin+1
to kmax-1 do
if a[i]>0 then k:=k+1; count:=k end; begin write('Введите размер массива '); readln(n); writeln('Введите элементы массива'); for i:=1 to n do read(a[i]); MinMax(n,a,kmin,kmax); if kmin > kmax then begin k:=kmin; kmin:=kmax; kmax:=k end; k:=Count(kmin,kmax,a); writeln('Количество положительных: ',k) end. Тестовые примеры для этой задачи должны содержать по крайней мере три следующих случая: – элемент a[kmin] расположен левее элемента a[kmax]; – элемент a[kmin] расположен правее элемента a[kmax]; – элементы a[kmin] и a[kmax] совпадают. Тестовые примеры Таблицы 1, 2, 3 иллюстрируют результаты к тестовым примерам. 1) n = 10, a = (6, -8, -10, 9, -1, 3, 5, 15, 12, 2), k = 3 Таблица 1 6
-8
Иллюстрация результатов тестового примера 1
-10
9
мин
+
-1
3
5
15
+
+
макс
27
12
2
2) n = 10, a = (6, -8, 15, 9, -1, 3, 5, -10, 12, 2), Таблица 2 6
-8
Иллюстрация результатов тестового примера 2
15
9
макс
+
-1
3
5
-10
+
+
мин
3) n = 10, a = (6, -8, -10, 15, -1, 3, 5, 9, 12, 2), Таблица 3 6
-8
k=3
12
2
k=0
Иллюстрация результатов тестового примера 3
-10
15
мин
макс
-1
3
5
9
12
2
Задача 8 Даны натуральное чётное число m и вещественный массив a из m элементов. Из массива a получить массивы b и c следующим образом. Выбрать из массива a два наиболее близких по значению элемента, меньший из них поместить в массив b, а больший – в массив c. Продолжить выбор из оставшихся элементов до полного заполнения массивов b и c.
Входные данные:
m – размер массива (чётное число), а – массив вещественных чисел.
Выходные данные:
b, c – массивы, полученные из массива a, n= m div 2 – размер массивов b и c.
28
Описание алгоритма В цикле выполняются следующие действия: – находятся два наиболее близких по значению элемента массива a, – меньший из найденных элементов помещается в массив b, больший –в массив c, – найденные элементы удаляются из массива a. Используются следующие процедуры: - MinPair – поиск двух элементов массива с наименьшим модулем разности между ними; - DelElement – удаление из массива элемента с заданным индексом; - WriteArr – вывод массива вещественных чисел; Текст программы program Vect_2; const nmax = 10; type
vect = array[1..nmax] of real;
var
a,b,c : vect;
n,m,i,k,p,r,ia,ib: integer; procedure MinPair(n: integer; const a: vect; var k,p: integer); var i,j:integer; x,y: real; begin x:=abs(a[1]-a[2]); k:=1; p:=2;
29
for i:=1 to n-1 do for j:=i+1 to n do begin y:= abs(a[i]-a[j]); if y<x then begin x:=y; k:=i; p:=j end end end; procedure DelElement(var n: integer; var a: vect; k: integer); var i: integer; begin for i:=k+1 to n do a[i-1]:=a[i]; n:=n-1 end; procedure WriteArr(n : integer; const a: vect); var i: integer; begin for i:=1 to n do write(a[i]:8:3, ' '); writeln end; begin writeln('Введите размер массива – чётное число '); readln(m); writeln('Введите элементы '); for i:=1 to m do read(a[i]); 30
n:=m div 2; ia:=0;ib:=0; for i:=1 to n do begin MinPair(m,a,k,p); if k>p then {k – индекс меньшего, p – индекс большего} begin r:=k; k:=p; p:=r end; ia:=ia+1; b[ia]:=a[k]; ib:=ib+1; c[ib]:=a[p]; {удаляется вначале элемент с большим индексом} DelElement(m,a,p); DelElement(m,a,k); end; writeln('Массив b'); writeArr(n,b); writeln('Массив c'); writeArr(n,c) end. Тестовые примеры 1) n = 10,
a = (1, 5, 20, 70, 25, 45, 8, 100, 15, 50)
b = (5, 20, 45, 1, 70), c = (8, 25, 50, 15, 100). 2) n = 6,
a = (2, 4, 6, 8, 10, 12)
b = (2, 6, 10), 3) n = 6,
c = (4, 8, 12)
a = (2, 2, 2, 2, 2, 2)
b = (2, 2, 2),
c = (2, 2, 2)
31
Задача 9 Дан массив, упорядоченный по неубыванию элементов. Вставить в массив последовательность из m элементов так, чтобы не нарушилась упорядоченность. Входные данные: n – размер массива, а – целочисленный массив, m – количество элементов последовательности. Выходные данные: а – целочисленный массив. Метод решения Определяется процедура вставки элемента в упорядоченный массив: procedure Ins_Sort(x: T_El; var n:integer; var a:vect); Поиск места для элемента x в массиве a осуществляется с одновременным сдвигом элементов вправо. Сдвиг продолжается до тех пор, пока выполняется условие: i > 0 и a i > x (используется упорядоченность массива). Далее a i +1 := x и n увеличивается на 1. Метод решения задачи заключается в просмотре каждого элемента последовательности и вставки его в упорядоченный массив. Текст программы program Vect_3; const nmax=10; type
T_El=integer; vect=array[1..nmax] of T_El;
var n,m,i:integer; a:vect; x:T_El; procedure Ins_Sort(x: T_El; var n:integer; var a:vect); var i:integer;
32
begin i:=n; while (i>0 ) and (a[i] > x) do begin a[i+1]:=a[i]; i:=i-1 end; a[i+1]:=x; n:=n+1 end; procedure OutPut(n:integer;const a: vect); var i:integer; begin for i:=1 to n do write(a[i], '
' );
writeln end; begin writeln('Введите размер массива'); read(n); writeln('Введите элементы '); for i:=1 to n do
read(a[i]);
writeln('Введите количество элем. последовательности'); read(m); writeln('Введите
элементы последовательности');
for i:=1 to m do begin read(x); Ins_Sort(x, n, a) end; OutPut(n, a) end. 33
Тестовые примеры 1) n = 3,
a = (4, 8, 12)
m=2 Элементы последовательности : (5, 11) a = (4 , 5, 8, 11, 12 ) 2) n = 5 ,
a = (3, 6, 8, 13, 20)
m=3 Элементы последовательности : (1, 4, 23) a = (1, 3, 4, 6, 8, 13, 20, 23) 3) n = 3,
a = (5 , 8, 9)
m= 4 Элементы последовательности : (12, 1, 6, 10) a = (1, 5, 6, 8, 9, 10, 12) 4.5 Двумерный массив Задача 10 По прямоугольной матрице построить вектор из сумм элементов, расположенных после максимального элемента в каждой строке матрицы. Входные данные: n, m – количество строк и столбцов матрицы, а – матрица вещественных чисел. Выходные данные: b – вектор, содержащий суммы элементов после максимального элемента в каждой строке матрицы. Описание алгоритма построения по матрице вектора В каждой строке матрицы (для i от 1 до n ): – найти k - номер максимального элемента, – найти сумму положительных элементов, расположенных после максимального элемента, – i–ому элементу вектора присвоить значение найденной суммы. 34
Алгоритм построения
по матрице вектора представлен процедурой
To_Vect. Текст программы program Matr_1; const
nmax=10;
type matrix=array[1..nmax,1..nmax] of real; vect=array[1..nmax] of real; var
a: matrix; b: vect;
n,m,i,j: integer; {процедура построения по матрице вектора} procedure To_Vect(n,m:integer;const a:matrix; var b:vect); var i,j,k:integer; s:real; begin for i:=1 to n do begin k:=1; for j:=2 to m do if a[i,j]>a[i,k] then k:=j; s:=0; for j:=k+1 to m do if a[i,j]>0 then s:=s+a[i,j]; b[i]:=s end end;
35
begin writeln('Введите размеры массива
');
readln(n,m); writeln('Введите элементы '); for i:=1 to n do for j:=1 to m do read(a[i,j]); To_Vect(n,m,a,b); for i:=1 to n do write(b[i]:7:3,' '); writeln end. Тестовые примеры 1)
n = 2, m = 3,
⎛1 2 3 ⎞ ⎟⎟ a = ⎜⎜ 4 5 6 ⎝ ⎠
b =( 0.000 0.000) 2)
n = 2, m = 3,
⎛8 2 3⎞ ⎟⎟ a = ⎜⎜ ⎝6 5 4⎠
b = ( 5.000 9.000) 3)
n = 2, m = 5,
⎛ 1 7 - 2 10 15 ⎞ ⎟⎟ a = ⎜⎜ 3 15 1 30 7 ⎝ ⎠
b = ( 0.000 0.000) 4)
n = 2, m = 5,
8⎞ ⎛15 - 2 10 - 7 ⎟⎟ a = ⎜⎜ 12 30 1 15 10 ⎝ ⎠
b = ( 18.000 25.000)
36
Задача 11 Удалить из матрицы строки и столбцы, на пересечении которых находится заданный элемент. Входные данные: n, m – количество строк и столбцов матрицы, а – матрица целых чисел, x – заданное значение. Выходные данные: а – матрица целых чисел. Метод решения Используются следующие процедуры: – Poisk – процедура поиска заданного значения x в матрице а: если элемент x найден, то i,j определяют место расположение его в матрице, если элемент x не найден, то i принимает значение n+1 procedure Poisk(n, m:integer; const a:matr; x:T_El; var i,j:integer); – Delet_El – процедура удаление из матрицы ki – той строки и kj – того столбца procedure Delet_El(ki,kj:integer; var n,m:integer; var a:matr); Метод решения задачи сводится к поиску значения x в матрице а и удалению i – той строки и j – того столбца до тех пор, пока i ≠ n+1. Текст программы program Matr_2; const nmax= 10; type
T_El= integer; matr= array[1..nmax,1..nmax] of T_El;
var
a: matr;
n,m,i,j: integer; x: T_El; 37
procedure Poisk(n,m:integer;const a:matr; x: T_el; var i,j:integer); begin i := 1; j := 1; while
(i <= n) and (x <> a[i,j]) do begin if j <= m
then j := j+1;
if j > m
then begin i:= i+1; j :=1 end
end end; procedure Delet_El(ki,kj:integer; var n,m:integer; var a:matr); begin for i:=1 to n do for j:=kj to m-1 do a[i,j]:=a[i,j+1]; m:=m-1; for i:=ki to n-1 do for j:=1 to m do a[i,j]:=a[i+1,j]; n:=n-1 end; procedure Output(n,m:integer; const a:matr); var i,j:integer;
38
begin for i:=1 to n do begin for j:=1 to m do write(a[i,j],'
');
writeln end end; begin writeln('Введите размеры массива read(n,m); writeln('Введите элементы '); for i:=1 to n do for j:=1 to m do read(a[i,j]); writeln('Введите элемент '); read(x); Poisk(n,m,a,x,i,j); while i<>n+1 do begin Delet_El(i,j,n,m,a); Poisk(n,m,a,x,i,j) end; if (n=0) and (m=0) then writeln('массив пуст') else Output(n,m,a) end. 39
');
Тестовые примеры 1) n = 4, m = 4,
⎛ ⎜ a=⎜ ⎜ ⎜ ⎝
1 2 3 4 ⎞ ⎟ 4 3 2 1 ⎟ , ⎟ 1 1 1 1 ⎟ 2 2 2 2 ⎠
Выходная матрица 2) n = 4,
x=4
⎛1 a = ⎜⎜ ⎝2
m = 4,
⎛1 ⎜ 4 a=⎜ ⎜1 ⎜ ⎝2
2 3 1 2
3 2 1 2
4⎞ ⎟ 1⎟ , ⎟ 1 ⎟ 2⎠
x =1
a = (2 )
Выходная матрица 3) n=3,
1⎞ ⎟ 2 ⎟⎠
m= 3,
⎛ 1 1 1⎞ ⎜ ⎟ a = ⎜ 2 1 1⎟ , x=1 ⎜ 2 2 1⎟ ⎝ ⎠ Массив пуст
⎛1 1⎞ ⎟⎟, 4) n =2, m = 2, a = ⎜⎜ 1 1 ⎠ ⎝
Выходная матрица
x=2
⎛1 1⎞ ⎟⎟ a = ⎜⎜ 1 1 ⎠ ⎝
40
ЛИТЕРАТУРА 1 Вальвачёв А.Н. Программирование на языке ПАСКАЛЬ для персональных ЭВМ ЕС. / А.Н. Вальвачёв, В.С.Крисевич. – Минск.: Вышэйшая школа, 1989. –223 с. – ISBN 5-339-00212-8. 2 Ван Тассел Д. Стиль, разработка, эффективность, отладка и испытание программ: Пер с англ. – 2-е изд., испр., - М.: Мир, 1985. – 332 с. 3 Грис Д. Наука программирования. М.: Мир, 1984. – 416 с. 4 Майерс Г.Искусство тестирования программ. – М.: Финансы и статистика, 1982. - 176 c. 5 Минакова Н.И.
Методы программирования.
Учебное пособие
/ Н.И.Минакова, Е.С. Невская, Г.А. Угольницкий, А.А. Чекулаева, М.И. Чердынцева. Методы программирования. – М.: Вузовская книга, 2000. –280 с. –ISBN 589522-038-X.
41