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

Вид материалаПрограмма

Содержание


Как с этим бороться.
Самостоятельная работа
Подобный материал:
1   2   3   4   5   6   7   8   9   10
Преобразование

1) x’ = x/(Right - Left)*Long_x – Left

2) y’ = Long_y - (y/(Up - Down)*Long_y – Down)

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

Для все точек функции выполнить

Берём очередную точку

Новая точка = Преобразование над очередной точкой

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


Первое. Если взялись строить график, стало быть, нам известна область, на которой мы будем строить график. Эта область конечна и её границы по координате x и есть величины Left, Right.

Предположим, что мы строим график на этой области по N точкам. Это означает, что в нашем распоряжении массив координат y для N точек. Наибольшее значение y в этом массиве есть величина Up и наименьшее значение y есть величина Down.

Тогда Long_x = Right – Left и Long_y = Up – Down.

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

Ввод границ области построения графика.

Ввод количества точек построения.

Расчёт шага построения.

Расчёт значений координат y

Расчёт максимума и минимума значений y – ков

Выполнение операций преобразования.

Выше появился термин “шаг построения”. Разумно строить точки следующим образом. Пусть самая левая точка графика – это левая граница области построения. Следующая точка это левая + шаг построения, то есть небольшое число. И каждая очередная точка это предыдущая + шаг построения. Если делать так, то координаты х можно не держать в массиве. Каждую координата можно рассчитать по очевидной формуле:

xi = Left + шаг * i если первую точку считать с номером 0 и

xi = Left + шаг * (i – 1) если первая точка имеет номер 1.

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

Важное замечание

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

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

Построение графика в окрестности точек разрыва

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

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

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

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

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

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

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

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

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

Max – верхняя граница значений ординат

Min – нижняя граница значений ординат.

Шаг – шаг изменения абсциссы.

А – начало области построения графика

В – конец области построения графика

Важное замечание. Нам важно не просто найти окрестность, а во-первых, достаточно точно определить абсциссу точки разрыва, а во-вторых, определить тип разрыва, а их может быть два:



Нестрогое описание процесса расчётов

Для поиска точек разрыва, мы пройдём всю область построения с шагом достаточно маленьким, но таким который позволит пройти всю область за разумное время. На каждом шаге процесс будет вычисляться новая абсцисса путем прибавления к предыдущей абсциссе величины шага. Для каждой вновь посчитанной абсциссы будем вычислять ординату, и если посчитанная ордината окажется за пределами отрезка [min, max] то будем предполагать, что найдена окрестность точки разрыва, после чего должен быть запущен процесс проверки этого предположения.

Min – это минимальная из уже посчитанных ординат и max – это максимальная из уже посчитанных ординат.

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

Строгое описание алгоритма.

Текущая точка = Началу области построения графика

Шаг = Начальное значение шага.

Номер точки разрыва = 0

Минимум = 0

Максимум = 0

Пока текущая точка не достигла конца области построения делать

Начало

Вычислить ординату текущей точки

Если ордината меньше минимума или больше максимума

То

Выполнить функцию поиска разрыва

Если разрыв найден

То

Прибавить к абсциссе текущей точки величину найденной окрестности точки разрыва.

Иначе

Если ордината больше максимума то максимум = ордината

Если ордината меньше минимума то минимум = ордината

Конец

Функция поиска точки разрыва

Шаг = Величина большая текущего шага.

Точка1 = текущая точка

Точка2 = Точка1+Шаг

Если Ордината1 > Ордината2 то Направление = вниз

Если Ордината1< Ордината2 то Направление = вверх

Есди Ордината1 = Ордината2

То результат функции = разрыв не найден, работу прекратить

Повторять

Точка1 = Точка2

Точка2 = Точка1 + Шаг

Если Ордината1 сильно отличается от ординаты2

То Результат функции = разрыв найден

Если Ордината1 > Ордината2 то Направление1 = вниз

Если Ордината1< Ордината2 то Направление1 = вверх

Если Направление1 <> Направление2

То Результат функции = разрыв найден

Конец цикла

Важное примечание

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

Думаю, вы обратили внимание, что некоторые понятие здесь не вполне определены. Например не ясно что означает фраза “Ордината1 сильно отличается от ординаты2”

Алгоритм построения графика функции:
  1. Ввести начало математической системы координат. Масштаб (количество пикселей в единичном отрезке).
  2. Нарисовать оси координат и сделать разметку (это может быть либо сетка, либо просто насечки на осях). Сделать оцифровку.
  3. Построить график. Для этого:
  • Перебрать все экранные координаты х (от 0 до 639).
  • Перевести каждый х – экранный в х – математический. (хэ=а+хм*m, откуда получаем хм=( хэ-а)/ m, где (а,в) – координаты точки начала математической системы координат, m – масштаб).
  • Проверить входит ли найденное хм в область определения функции, график которой мы строим.
  • Вычислить умм=f(хм)).
  • Перевести ум в уээ=round(b- ум)).
  • Изобразить точку с координатами (хэ, уэ) на экране монитора.

Задачи: Построить графики функций: у=х2; у=sinx; у=; у=1/х.

Диаграммы.

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

Алгоритм построение столбчатой диаграммы:
  1. Ввести массив из чисел.
  2. В исходном массиве найти максимальный элемент, и для него определить масштаб для построения столбиков (например, l=round(450/max)).
  3. По количеству элементов определить ширину каждого столбика диаграммы (например, m=round(600/n), где n – количество элементов массива).
  4. Строить каждый столбик, для чего использовать процедуру изображения прямоугольника, размеры которого определяются следующим образом: ширина стандартна для всех – это m, высота определяется индивидуально для каждого числа, например h=l*a[i].
  5. Возле каждого столбика проставлять его числовое значение и порядковый номер (пользоваться функцией str).

Задача: Построить столбчатую диаграмму, если в исходном массиве есть еще и отрицательные числа.

{Пример построения столбиковой диаграммы}


program BarDiagram;

uses crt,graph;

{N - количество элементов исходных данных}

{Name - наименования элементов исходных данных}

{Num - числовые значения элементов исходных данных}

const

N=6;

Name:array[1..N] of string=('1997','1998','1999','2000','2001','2002');

Num:array[1..N] of integer=(10,5,8,11,2,7);

var

Dr,Rg,MaxX,MaxY,X0,Y0,S,I,X1,Y1,X2,Y2,S1:integer;

M:real;

Nm:string;

begin

{Инициализация графического режима}

Dr:=detect;

initgraph(Dr,Rg,'');


{Определение начальных параметров}

cleardevice; {Очистка экрана}

MaxX:=getmaxx; {Определение максимальной координаты по X}

MaxY:=getmaxy; {Определение максимальной координаты по Y}

X0:=40; {Отступ от края экрана до рамки по вертикали}

Y0:=20; {Отступ от края экрана до рамки по горизонтали}

S:=round((MaxX-4*X0)/N); {Определение ширины одного столбца}

X1:=2*X0+2; {Начальная координата по X для первого столбца}

Y1:=MaxY-2*Y0+2; {Конечная координата по Y для всех столбцов}

X2:=X0+2; {Координата по X для вывода значений слева оси Y}


{Рисование рамки}

setfillstyle(1,1);

bar(X0,Y0,MaxX-X0,MaxY-Y0);

setcolor(14);

rectangle(X0,Y0,MaxX-X0,MaxY-Y0);


{Рисование осей}

line(2*X0,2*Y0,2*X0,MaxY-2*Y0); {Ось Y}

line(2*X0,MaxY-2*Y0,MaxX-2*X0,MaxY-2*Y0); {Ось X}


{Поиск наибольшего из значений элементов исходных данных в переменную M}

M:=Num[1];

for I:=2 to N do

if Num[I]>M then

M:=Num[I];


S1:=round((MaxY-4*Y0)/M); {Определение длины единичного отрезка на оси Y}


{Рисование диаграммы}

for I:=1 to N do

begin

Y2:=2*Y0+(MaxY-2*Y0-S1*Num[I]); {Начальная координата по Y}

str(Num[I]:4,Nm);

outtextxy(X2,Y2,Nm); {Вывод значения элемента данных слева оси Y}

line(2*X0-3,Y2-3,2*X0,Y2-3); {Рисование деления на оси Y}

outtextxy(X1,Y1,Name[I]); {Вывод названия элемента данных под осью X}

setfillstyle(1,I+1); {Определение типа заполнения столбца}

bar(X1-1,Y2-3,X1-1+S,Y1-3); {Рисование столбца}

X1:=X1+S; {Начальная координата по Х для очередного столбца}

end;

repeat

until keypressed;

closegraph {Выход из графического режима}

end.

{Пример построения линейной диаграммы}


program LineDiagram;

uses crt,graph;

{N - количество элементов исходных данных}

{Name - наименования элементов исходных данных}

{Num - числовые значения элементов исходных данных}

const

N=6;

Name:array[1..N] of string=('1997','1998','1999','2000','2001','2002');

Num:array[1..N] of integer=(10,5,8,11,2,7);

var

Dr,Rg,MaxX,MaxY,X0,Y0,S,I,X1,Y1,X2,Y2,S1,X3,Y3,X4,Y4:integer;

M:real;

Nm:string;

begin

{Инициализация графического режима}

Dr:=detect;

initgraph(Dr,Rg,'');


{Определение начальных параметров}

cleardevice; {Очистка экрана}

MaxX:=getmaxx; {Определение максимальной координаты по X}

MaxY:=getmaxy; {Определение максимальной координаты по Y}

X0:=40; {Отступ от края экрана до рамки по вертикали}

Y0:=20; {Отступ от края экрана до рамки по горизонтали}

S:=round((MaxX-4*X0)/N); {Определение интервала между точками по X}

X1:=2*X0+2; {Координата по X для первой точки диаграммы}

Y1:=MaxY-2*Y0+2; {Координата по Y для вывода названий под осью Y}

X2:=X0+2; {Координата по X для вывода значений слева от оси Y}


{Рисование рамки}

setfillstyle(1,1);

bar(X0,Y0,MaxX-X0,MaxY-Y0);

setcolor(14);

rectangle(X0,Y0,MaxX-X0,MaxY-Y0);


{Рисование осей}

line(2*X0,2*Y0,2*X0,MaxY-2*Y0); {Ось X}

line(2*X0,MaxY-2*Y0,MaxX-2*X0,MaxY-2*Y0); {Ось Y}


{Поиск наибольшего из значений элементов исходных данных в переменную M}

M:=Num[1];

for I:=2 to N do

if Num[I]>M then

M:=Num[I];


S1:=round((MaxY-4*Y0)/M); {Определение длины единичного отрезка на оси Y}


{Рисование диаграммы}

for I:=1 to N do

begin

Y2:=2*Y0+(MaxY-2*Y0-S1*round(Num[I])); {Координата точки по Y}

X4:=X1-1; {Конечная координата линии по X}

Y4:=Y2-3; {Конечная координата линии по Y}

str(Num[I]:4,Nm);

outtextxy(X2,Y2,Nm); {Вывод значения элемента данных слева оси Y}

line(2*X0-3,Y2,2*X0,Y2); {Рисование деления на оси Y}

outtextxy(X1,Y1,Name[I]); {Вывод названия элемента данных под осью X}

setlinestyle(0,1,1); {Определение типа линии диаграммы}

circle(X4,Y4,2); {Рисование узлов диаграммы}

if I<>1 then

line(X3,Y3,X4,Y4); {Рисование линии диаграммы}

X3:=X1-1; {Начальная координата линии по X}

Y3:=Y2-3; {Начальная координата линии по Y}

X1:=X1+S; {Координата по X для очередной точки}

end;

repeat

until keypressed;

closegraph {Выход из графического режима}

end.

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

Построение круговой диаграммы.

{Пример построения круговой диаграммы}


program RoundDiagram;

uses crt,graph;

{N - количество элементов исходных данных}

{Name - наименования элементов исходных данных}

{Num - числовые значения элементов исходных данных}

const

N=6;

Name:array[1..N] of string=('1997','1998','1999','2000','2001','2002');

Num:array[1..N] of integer=(10,5,8,11,2,7);

var

Dr,Rg,MaxX,MaxY,Y0,I,S1,Kg,Xc,Yc,R,Yk:integer;

M,S:real;

begin

{Инициализация графического режима}

Dr:=detect;

initgraph(Dr,Rg,'');


{Определение начальных параметров}

cleardevice; {Очистка экрана}

MaxX:=getmaxx; {Определение максимальной координаты по X}

MaxY:=getmaxy; {Определение максимальной координаты по Y}

Xc:=300; {Координата центра диаграммы по X}

Yc:=250; {Координата центра диаграммы по Y}

R:=150; {Радиус диаграммы}


{Рисование рамки}

setfillstyle(1,1);

bar(0,0,MaxX,MaxY);

setcolor(14);

rectangle(0,0,MaxX,MaxY);


{Определение суммы значений элементов исходных данных в переменную S}

S:=0;

for I:=1 to N do

S:=S+Num[I];


{Рисование диаграммы}

Y0:=0; {Начальный угол сектора}

for I:=1 to N do

begin

Kg:=round(360*(Num[I]/S)); {Определение кол-ва градусов в секторе}

Yk:=Y0+Kg; {Конечный угол сектора}

if Yk>360 then

Yk:=360;

setfillstyle(1,I+1); {Определение типа заполнения сектора}

pieslice(Xc,Yc,Y0,Yk,R); {Рисование сектора}

Y0:=Yk {Начальный угол сектора}

end;

repeat

until keypressed;

closegraph {Выход из графического режима}

end.

Работа с файлами.

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

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

Объявление файловой переменной в разделе описания переменных имеет вид :

var <имя файла>: File of <тип элементов>;

Например:

var Ft : File of integer;

M : File of char;


Type File_integer=File of integer

File_char=File of char;

Var F1: File_integer;

F2: File_char;

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

С каждым файлом связан так называемый файловый указатель. Это неявно описанная переменная, которая указывает на некоторый элемент файла.

(0)

(1)

...

(к)

(к+1)

...













































файловый указатель


Все операции производятся с элементом, который определен файловым указателем.

Связь переменной файлового типа

с файлом на диске.

Процедура Assign(<имя файловой пер-ой>,’<имяфайла на диске>’);

Например:


Assign(F1,’A:INT.DAT’);


После установления такого соответствия все операции, выполняемые над переменной F1, будут выполнятся над файлом, хранящимся на диске А и имеющим имя INT.DAT

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

Чтение из файла.

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

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

Reset(<имя файловой переменной>);

Собственно чтение данных из файла выполняется процедурой

Read(<имя файловой переменной>,<имя переменной>);

Переменная должна иметь тот же тип, что и компоненты файла. Отметим, что если оператор ввода имеет вид Read(<имя переменной>), то данные вводятся с клавиатурой, а если Read(<имя файловой переменной>,<имя переменной>); то данные вводятся из файла, хранящегося на диске.

Закрытие файла

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

Close(< имя файловой переменной>)

Общая схема чтения данных из файла, таким образом, следующая:

Reset(<имя файловой переменной>);

.......

Read(<имя файловой переменной>,<имя переменной>);

...........

Close(<имя файловой переменной>);


Признак конца файла

Так как число элементов файла не известно заранее, необходимо уметь определять, что файл кончился. Для этого используется логическая функция Eof(<имя файловой переменной>) (Eof - End Of File). Она принимает истинное значение (Тrue), если достигнут конец файла, и ложное (False) - в противном случае.

Пример Прочитаем из файла целые числа и выведем их на экран:

Assign(F1,’A:INT.DAT’);

Reset(F1);

While Not Eof(F1) do

begin

read(f1,n); { считываем очередное число из файла}

write(n,’ ‘); { выводим его на экран}

end;

Close(F1);

Запись в файл

Под записью в файл понимается вывод результатов программы из оперативной памяти ЭВМ в файл на диске.

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

Rewrite(< Имя файловой переменной >);

Собственно запись данных в файл выполняется процедурой :

Write(<имя файловой переменной>,<значение>);

Общая схема записи данных в файл, таким образом, следующая:

Rewrite(<>);

......

Write(<имя файловой переменной>,<значение>);

..........

Close(<имя файловой переменной>);

Прямой доступ к элементам файла

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

Установка указателя.

Процедура Seek(<имя файловой переменной>,N) устанавливает файловый указатель на N-й элемент. Например, Seek(F1,3). (на 4 элемент)

Определение номера элемента

Функция FilePos(<имя файловой переменной>) возвращает номер элемента, на который «смотрит» файловый указатель.

Определение количества элементов в файле

Функция FileSize(<имя файловой переменной>) возвращает количество элементов в файле.

Удаление и переименование файлов

Erase(<имя файловой переменной>) процедура удаления файла.

Rename(<имя файловой переменной>,’<новое имя на диске>’) переименование файла.


Пример : В файле DAT1.DAT записаны целые числа. Вычислить сумму элементов файла и результат вместе с исходными данными записать в файл DAN2.DAT

Program WW;

Var f1,f2 : file of integer;

s, n : integer;

begin

Assign(f1,’DAT1.DAT’);

Reset(F1);

Assign(f2,’DAT2.DAT’);

Rewrite(f2);

s:=0;

While Not Eof(f1) do { проверка на конец файла}

begin

read(f1,n); {чтение элемента из файла F1}

write(f2,n); { запись элемента в файл F2}

s:=s+n;

end;

write(f2,s); {запись суммы элементов в конец файла F2}

write(‘Результат находится в файле DAT2.DAT’);

Close(f1);

Close(f2);

end.

Текстовые файлы

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

Var A: Text;

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

Для чтения данных применяется процедура Read. Если необходимо после чтения данных перейти на следующую строку, то используется процедура Readln. Если необходимо просто перейти к следующей строке, то можно использовать процедуру Readln(<имя файловой переменной текстового файла>); которая устанавливает файловый указатель на первый элемент следующей строки.

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

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

Процедура Append(<имя файловой переменной текстового файла>). Она открывает файл для «дозаписи», помещая файловый указатель в конец файла.

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

Решение: Пусть в файле содержится следующая информация:

-32 16 0 8 7

4 5 9 13 11 -5 -8

6 -8 0 -12

5 4 3 2 1 12

1 2

Этот файл можно создать в среде Турбо Паскаль следующим образом:
  • создайте новый файл посредством команды New меню File;
  • запишите все числа, разделяя их пробелами, и разбейте на строки, как указано в задании;
  • сохраните файл, например, под именем INT1.DAT

теперь напишем программу

program rrr;

var f : text;

x, k: integer;

begin

Assign(f,’int1.dat’);

Reset(f);

While Not Eof(f) do {пока не достигнут конец файла}

begin

k:=0;

While Not Eoln(f) do {пока не достигнут конец строки}

begin

read(f,x); {считываем очередное число}

write(x,’ ‘); {выводим его на экран}

Inc(k); {увеличиваем счетчик}

end;

writeln(‘в строке’, k, ‘ элементов’);

Readln(f) {переходим к следующей строке файла}

end;

Close(f);

end.


Пример. Записать двумерный массив вещественных чисел 5х4 в тестовый файл.

Program mas;

const m=5; n=4;

Var fil : text;

a: real;

s: char;

i,j : integer;

begin

Assign(fil,’massiv.txt’);

Rewrite(fil);

for i:=1 to m do

begin

for j:=1 to n do

begin

a:=random(100);

write(fil,a:5:3,’ ‘); {число записывается в файл в указанном формате, за ним пробел}

end;

writeln(fil); {переход в файле на новую строку}

end;

Close(fil);

{Чтение файла и вывод матрицы на экран по строкам}

Reset(fil); {открытие уже имеющегося файла}

while not Eof(fil) do

begin

while not Eoln(fil) do

begin

read(fil,a); {чтение числа}

write(a:5:3);

read(fil,s); { чтение пробела после числа}

write(s);

end;

writeln;

readln(fil);

end;

Close(fil);

end.


Пример. Дан текстовый файл f. Переписать в файл g все компоненты исходного файла f в обратном порядке.

program tofile;

var f, g : text;

n, i, j : integer;

s : string;

x : array [1..32000] of char;

begin

assign(f,’f.txt’); assign(g,’g.txt’);

rewrite(g); rewrite(f);

writeln(‘Введите число строк в создаваемом вами файле ‘);

readln(n);

writeln(‘вводите строки, после введения каждой нажмите Enter’);

for i:=1 to n do begin readln(s); write(f,s); end;

reset(f);

i:=0;

writeln(‘Исходный файл :’);

while(not eof(f)) and (i<32000) do

begin i:=i+1; read(f,x[i]); write(x[i]); end;

writeln;

writeln(‘Измененный файл :’);

for j:=i downto 1 do

begin write(g,x[j]); write(x[j]); end;

writeln;

close(f); close(g);

end.


Задача. Дан текстовый файл. Вставить в начало каждой строки ее номер и записать преобразованные строки в новый файл.

Задача. Даны два текстовых файла. Записать в третий файл только те строки, которые есть и в первом, и во втором файлах.

Запись.

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

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

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

Запись - это структурированный тип, описывающий набор данных разных типов. Составляющие запись объекты называются ее полями. Каждое поле имеет уникальное (в пределах записи) имя. Чтобы описать запись, необходимо указать ее имя, имена объектов, составляющих запись, и их типы.

Общий вид описания записи :

Type <имя записи> = Record

<поле 1> : <тип 1>;

<поле 2> : <тип 2>

<поле n> : <тип n>

End;

Применительно к рассматриваемой задаче запись можно описать так :

Type

pupil = Record

fam : string[15]; {поле фамилии}

b1,b2,b3,b4,b5 : 2..5; {поля баллов}

sb : Real {средний бал}

End;

Чтобы хранить в памяти ЭВМ информацию обо всех 25 учениках класса, необходимо ввести массив klass - массив записей.

Var klass : array[1..25] Of pupil;

Доступ к полям записи можно осуществить двумя способами:

1. С указанием имени переменной и имени поля. Например, klass[2].fam, klass[3].sb, klass[1].b4

Ввод фамилий и оценок учащихся, т.е. элементов массива klass, можно записать так:

for i:=1 to 25 do

begin

readln(klass[i].fam);

readln(klass[i].b1);

readln(klass[i].b2);

readln(klass[i].b3);

readln(klass[i].b4);

readln(klass[i].b5);

end;

2. С использованием оператора присоединения.

Имеется возможность осуществлять доступ к полям записи таким образом, как если бы они были простыми переменными. Общий вид оператора присоединения:

With <имя записи> Do <оператор>;

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

Пример

for i:=1 to 25 do

With klass[i] do

begin

readln(fam);

readln(b1,b2,b3,b4,b5);

end;

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

program zap;

Type pupil = Record

fam : string[15]; {поле фамилии}

b1,b2,b3,b4,b5 : 2..5; {поля баллов}

sb : Real {средний бал}

End;

Var klass : array[1..25] Of pupil;

p: pupl;

i,m : integer;

sbmax : real;

begin

for i:=1 to 25 do

with klass[i] do

begin

writeln(‘Введите фамилию и пять оценок’);

readln(fam);

readln(b1,b2,b3,b4,b5);

end;

for i:=1 to m do {вычисление среднего балла}

with klass[i] do sb:=(b1+b2+b3+b4+b5)/5;

sbmax:=0;

{ поиск максимального среднего балла}

for i:=1 to m do

if klass[i].sb>=sbmax then sbmax:=klass[i].sb;

for i:=1 to m do {печать результатов}

if klass[i].sb=sbmax

then with klass[i] do writeln(fam:20,’ - ‘, sb:6:3);

end.

Пример. Определите дату завтрашнего дня.

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

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

1 2 1997

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

Type year=1500..2000;

month=1..12;

day=1..31;

data = Record

y : year;

m : month;

d : day;

end;

Заметим, что :
  • если дата соответствует не последнему дню месяца, то год и месяц не изменяются, а число увеличивается на 1;
  • если дата соответствует последнему дню месяца, то :

а) если месяц не декабрь, то год не изменяется, месяц увеличивается на 1, а число устанавливается в 1;

б) если месяц - декабрь, то год увеличивается на 1, а месяц и число устанавливаются в 1.

Program datanext;

Type year=1500..2000;

month=1..12;

day=1..31;

data = Record

y : year;

m : month;

d : day;

end;

Var dat, next : data;

Function leap(yy:year):boolean; {функция определяет

високосный ли год}

begin

leap:=(yy Mod 4=0) And (yy Mod 400 <>0);

end;

Function Dmonth(mm:month; yy : year) : day; {функция определения

количества дней данного месяца в данном году}

begin

case mm of

1,3,5,7,8,10,12: Dmonth:=31;

4,6,9,11 : Dmonth:=30;

2 : if leap(yy) then Dmonth:=29 else Dmonth:=28;

end;

end;

procedure Tomorrow(td : data; var nd : data); {опр-ние завтрашней даты}

begin {если это не последний день месяца}

if td.d<> Dmonth(td.m, td.y) then

with nd do

begin

d:=td.d+1;

m:=td.m;

y:=td.y;

end;

else {если это последний день месяца}

if td.m=12 then {если это декабрь}

with nd do

begin

d:=1;

m:=1;

y:=td.y+1;

end;

else { если это не декабрь}

with nd do

begin

d:=1;

m:=td.m+1;

y:=td.y;

end;

end;

BEGIN

writeln(‘Введите сегодняшнее число, месяц и год’);

readln(dat.d, dat.m, dat.y);

Tomorrow(dat,next);

writeln(‘завтра будет’);

writeln(next.d, ‘.’, next.m, ‘.’, next.y);

END.

Задачи:
  1. Фамилии и имена 25 учеников класса записаны в двух различных таблицах. Напечатать фамилию и имя каждого ученика на отдельной строке.
  2. Названия 20 футбольных клубов и городов, которые они представляют, записаны в двух различных таблицах. Напечатать название и город каждого клуба на отдельной строке.
  3. Даны названия 26 городов и стран, в которых они находятся. Среди них есть города, находящиеся в Италии. Напечатать их названия.
  4. Известны данные о 16 сотрудниках фирмы: фамилия и отношение к воинской службе (военнообязанный или нет). Напечатать фамилии всех военнообязанных сотрудников.
  5. Известны данные о мощности двигателя (в л.с.) и стоимость 30 легковых автомобилей. Определить общую стоимость автомобилей, у которых мощность двигателя превышает 100 л.с.
  6. Известны данные о цене и тираже каждого из 15 журналов. Найти среднюю стоимость журналов, тираж которых меньше 10000 экземпл.
  7. Известны данные о массе и объеме 30 чел, изготовленных из различных материалов. Определить максимальную плотность материала тел.
  8. Известны вес, пол, рост каждого из 22 человек. Найти общую массу и средний рост мужчин.
  9. Известно количество очков, набранных каждой из 20 команд - участниц первенства по футболу. Ни одна пара команд не набрала одинакового количества очков.

а) Определить название команды, ставшей чемпионом.

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

в) Определить названия команд, занявших первое и второе места, не используя при этом двух операторов цикла (два прохода по массиву).

г) Вывести названия команд в соответствии с занятыми ими местами в чемпионате.
  1. Известны оценки каждого из 25 учеников класса по десяти предметам. Найти фамилию одного из учеников :

а) имеющих наибольшую сумму оценок;

б) имеющих наименьшую сумму оценок.
  1. Известны баллы, набранные каждым из 20 спортсменов-пятиборцев в каждом из пяти видов спорта. Определить фамилию спортсмена - победителя соревнований.
  2. Известны данные о 20 учениках класса: фамилии, имена, отчества, даты рождения (год, номер месяца и число). Определить, есть ли в классе ученики, у которых сегодня день рождения, и если да, то напечатать имя и фамилию каждого.