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

Иванова Г.С. - Основы программирования

.pdf
Скачиваний:
2771
Добавлен:
02.04.2015
Размер:
13.53 Mб
Скачать

 

 

4, Структурные типы данных

 

 

тень

хк

тень

хк

 

тень

хк

x[i,l]

 

x[i,2]

x[U]

x[i,2]

x[i,l]

x[i,2]

S:= S+x[i,2]-xk

S:=S+x[i,2]-x[i,l]

S и X- не

xk:=x[i,2]

 

xk:=x[i,2]

 

меняются

Рис. 4.25. Три случая добавления i-ro отрезка к «тени»:

а- отрезок частично перекрыт «тенью»; б - отрезок не перекрыт «тенью»;

в- отрезок полностью перекрыт «тенью» (в);

S - уже накопленная «тень», хк - правая граница этой «тени»

екций.) Количество отрезков п. Отрезки заданы координатами начала и кон­ ца проекций на ось х.

Анализ условия задачи и возможных вариантов отрезков показывает, что решение задачи «в лоб» достаточно сложно. В то же время, если бы отрезки были сортированы по левой границе, то вычисление тени можно было вы­ полнять, добавляя отрезки по одному. При этом можно было бы выделить три случая (рис. 4.25).

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

Program ten;

Var х:array[1. .100J..2] of real; iJ,n,k:integer; xk,SyW:real;

Begin

Write('Beedume количество отрезков: *); Readln(n);

WriteLnCВводите начала и концы отрезков. *); for i:==I to n do ReadLn(x[iyl],x[i,2]);

{сортировка отрезков по возрастанию левой границы} yV=7; к:=1;

while к<>0 do

begin

к:=0;

for i:=J to n-j do

 

 

ifx[ij]>x[i-^lj]then

 

 

begin k:=k-^I;

{меняем отрезки местами }

w:=x[ij]; x[ij]:^x[i-^lj];

x[i+l,l]:==w;

w: =xfi, 2J; x[l 2]: =xfi+J, 2J; xfi+ 7,2J: =w;

end;

111

Часть L Основы алгоритмизации и процедурное программирование

end;

 

{определение тени}

 

S:'=x[l,2]'X[lJ];

(длина первого отрезка}

xk:=x[]JJ;

{правая граница первого отрезка}

for i:=2 to п do

 

ifxfi, 1]> =xk then

{случай б}

begin S: =S-^xfi,2]'X[i, 1]; xk:=x[i,2J;

end

else ifx[i,2J>xk then {случай a} begin S: =S+xfi, 2J'Xk; xk:=xfi,2J;

end;

WriteIn('Длина тени равна \ S:6:2); End.

Задания для самопроверки

Задание 1. Дана матрица вещественного типа D(n,m), п, m < 20. Разработайте программу, которая в заданной матрице вычеркивает все строки, содержащие более трех отрицательных элементов. Вывести на печать исходную матрицу и матрицу-ре­ зультат или соответствующие сообщения, если таких строк не окажется или все строки будут удовлетворять условию.

Задание 2. Дана матрица A(n,m), п, m < 15. Разработайте программу, формиру­ ющую одномерный массив В(п), элементами которого должно являться количество элементов каждой строки, превышающих среднее арифметическое значение матри­ цы в целом. Если в строке таких элементов нет, в соответствующий элемент одно­ мерного массива заносится 0. Вывести исходную матрицу, значение среднего ариф­ метического элементов матрицы и сформированный массив В.

Задание 3. Разработайте программу, формирующую квадратную матрицу D(n,n), п < 15, элементы которой определяются по формуле

 

I

sin(i+j)

npHi<j;

D[iJ]=

 

1

npHi=j;

 

I

(i+j)/(2i+3j)

npHi>j,

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

112

4. Структурные типы данных

4.5. Строки

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

Синтаксическая диаграмма объявления строкового типа данных пред­ ставлена на рис. 4.26.

Целое без знака - это максимальная длина строки, которая не должна превышать 255 байт. Если длина не указана, то по умолчанию принимается максимальное значение - 255 символов.

Объявление переменных строкового типа, так же как и массивов, можно выполнить двумя способами:

• в операторе объявления переменных, например:

Var Sly S2:string[40]; {символьные строки длиной 40 байт} S3:strmg: {символьная строка длиной 255 байт}

• с предварительным объявлением типов, например:

Туре S40 = strmg[40]; {тип - строка длиной 40 байт}

ST = string; {тип - символьная строка длиной 255 байт} Var SJ,S2: S40; {символьные строки типа S40}

S3:ST; {символьная строка типа ST}

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

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

— « / string V j -

^

f

\ J ^

I без знака |

v L /

Рис. 4.26. Синтаксическая диаграмма <Объявление строкового типа>

113

Часть 1. Основы алгоритмизации и процедурное программирование

Максимальная длина строки ^ 255

А

[ s i

1

lAJщ с|_

_^н^II

1 М 1 1 )

0

2

3

4

5

6

7

8

9

10 11

12 13 ...

 

V

Текущая

Незанятая

часть строки

длина строки

 

Рис. 4.27. Внутреннее представление строки

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

Const S:strmgf40]= Типизированная константа V

SJ:string= '*;... {пустая строка нулевой длины}

Операции над переменными строкового типа. Над переменными строкового типа помимо операции доступа к символам определены операции присваивания, конкатенации (сцепления) и отношений.

Доступ к сглмволам строки. Обращение к символам строки выполняет­ ся как к элементам массива символов, т. е. с указанием имени строки и номе­ ра элемента, например st[l] или s[i]. Нулевой байт содержит текущее значе­ ние длины строки, но так как строка - это массив символов, длина автомати­ чески интерпретируется как символ. Для получения текущей длины строки в виде числа необходимо явное преобразование символьного типа в целый. Например, если i - переменная целого типа, а S3 - переменная строкового типа, то получить текущую длину строки S3 можно:

1)/. = byte(S3[0]); {явное преобразование с помощью автоопределения}

2)i:-ord(S3[0]): {явное преобразование с помощью специальной функции}

Однако лучше это сделать, используя специальную функцию Length, описанную ниже.

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

S1:- 'ABCD V {присваиваем строке значение строковой константы}

52.= V

{присваиваем строке значение символа}

5.-=57;

{переписываем одну CTpoiQ^ в другую}

При присваивании строке значения символа последний интерпретирует­ ся как строка единичной длины. Если строка-источник длиннее, то при при­ сваивании она усекается в соответствии с длиной строки-результата.

114

4. Структурные типы данных

Конкатенация, Операция конкатенации позволяет сцепить строки с дру­ гими строками или символами. При сцеплении длины строк суммируются, а символы объединяются в одну последовательность. Например:

*fdc'+ 'ghj V {получаем ' fdcghj'}

S4+ Vvv V {к строке S4 дописывается 'vvv'}

Результат этой операции можно присвоить какой-либо строке или выве­ сти на экран.

Отношения. Над строками допускается выполнять операции отноше­ ния: = , о , >, <, >=, <=. Сравнение строк при этом выполняется последова­ тельно слева направо с учетом внутренней кодировки символов до первого несовпадающего символа. Большей считается та строка, код несовпадающе­ го символа которой по таблице ASCII больше. Если длина одной строки меньше другой, то недостающие значения до длины большей строки запол­ няются символами #0. Результатом операций отношения для строк, как и для чисел, является значение false и true.

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

Так, если

S4:='ABCD'; S3:='ADFH'; C:='L';

то при выполнении операций отношения:

S4 = S3 {получим false}

S4 > S3 {получим false}

S3 > S4 {получим true}

S3 = С {получим false}

Ввод-вывод строк. Ввод-вывод переменных строкового типа осуществ­ ляется одной операцией Read (ReadLn) или Write (WriteLn), например:

ReadLn(S]);

WriteLn(Sl):

При вводе за строку принимается последовательность символов до кода клавиши ENTER. Если длина введенной строки больше указанной макси­ мальной длины, то лишние символы отбрасываются, а в нулевой байт запи­ сывается значение максимальной длины. В противном случае в нулевой байт записывается количество введенных символов. Поскольку строкой считают­ ся все символы до кода клавиши ENTER, ввести в одной строке строковое значение, а затем, например, число нельзя.

Если при вводе строки просто нажать клавишу Enter, не вводя никаких символов, то считается, что введена пустая строка.

115

Часть L Основы алгоритмизации и процедурное программирование

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

ифункций.

1.Функция Length(st):word- возвращает длину строки st, например:

n:=Length(stl); {целочисленной переменной п присваивается значе­ ние длины строки}

2. Процедура Delete(sU index, count) - удаляет count символов строки st, начиная с символа с номером index, например:

S1: = ^dddddsssssfffff;

Delete(Sl,6,5); {получим результат 'dddddfflfff'}

3. UpoixQjjypa. Insert(St2,Stl,index) - вставляет подстроку символов St2 в строку Stl, начиная с символа с номером index. Процедура обычно использу­ ется при формировании строк, включающих числовую информацию, напри­ мер:

SJ = 'dddddddddd'; S2 = 'аааааа';

Insert(Sl, S2,6); {получим 'dddddaaaaaaddddd'} Insert(Tas\ S2,6); {получим 'dddddPasaaaaaaddddd'}

4. Процедура Str(x[:w [:d]], St) - преобразует результат выражения x в строку st, содержащую запись этого числа в виде последовательности симво­ лов (как при выводе).

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

Значение w, если оно указано, интерпретируется как длина строки, а значение d, если оно указано - как количество цифр дробной части для веще­ ственных чисел, например:

х:=-5.67;

Str(x:7:3,sl); {получим строку ' -5.670'}

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

5. Процедура Val(St, х, Code) - преобразует строку St с записью числа в виде последовательности символов во внутреннее представление целого или вещественного числа и помещает его в переменную х. В целочисленной пе­ ременной Code процедура возвращает код ошибки: О, если преобразование прошло успешно, и номер ошибочного символа, если строка st не являлась допустимой формой записи числа.

116

4. Структурные типы данных

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

Var S:strmg; Code:mteger; a:real; ...

.„repeat

Write('Beedume число a:');

ReadLn(S);

{вводим строку}

Val(S,afCode);

{пытаемся преобразовать строку в число}

ifCodeoOthen

 

WriteLn('Число введено не верно *);

until Code-0;...

{до получения правильного значения числа}

6. Функция Copy(St,index,count):string - возвращает фрагмент строки St длиной count символов, начиная с символа с номером index, например:

S1 = 'qqqEEEEEEuuuuu';

S:= Copy(SlJ,6); {получим строку 'ЕЕЕЕЕЕ'}

7. Функция Pos(St2,Stl):integer - возвращает номер позиции первого вхождения подстроки St2 в строку Stl. Если вхождение не найдено, то функ­ ция возвращает О, например:

S] = 'qqqEEppEEuuuuu':

i:= Pos('EE\Sl); {получим i=4}

8. Функция UpCase(ch):char - возвращает символ, соответствующий символу верхнего регистра для ch, если таковой имеется, либо сам символ ch, если для него не определен символ верхнего регистра.

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

Пример 4.14. Дана строка не более 40 символов, состоящая из слов, раз­ деленных пробелами. Разработать программу удаления «лишних» пробелов. Лишними считать пробелы в начале строки до первого символа, второй и бо­ лее пробелы между словами и пробелы в конце строки.

При решении данной задачи с использованием строкового типа отпада­ ет необходимость посимвольного анализа строки. Функция Pos, которой в качестве подстроки заданы два пробела подряд, позволит определить все ме­ ста в строке, где записаны несколько пробелов подряд. Поочередно удалив лишние пробелы, получим строку, в которой останется только проверить и при необходимости удалить пробел в начале и пробел в конце (рис. 4.28). Ни­ же приведен текст программы.

Program ex;

Var st:string[40]; k:byte;

117

Часть I. Основы алгоритмизации и процедурное программирование

 

1.

нет

delete

(St, 1,1)

 

k:=length{st)

 

:st[k] = 'J>

1

нет

delete

(st,k,l)

( Конец J

Рис. 4.28. Схема алгоритма программы удаления «лишних» пробелов

Begin

WriteLnCВведите строку длиной <= 40 символов');

ReadLn(st):

 

 

 

Write(*Введенная строка:');

 

WriteLn(^);

 

 

 

k:-posC^^ \st);

{проверяем, есть ли сдвоенные пробелы?}

while к<>0 do

{пока есть сдвоенные пробелы}

begin

 

 

 

 

delete(st,k,l);

{удаляем первый пробел}

k:=posC^^ ^,st); {проверяем, есть ли сдвоенные пробелы?}

end;

 

 

 

 

ifst[l]=

^^^ then delete(stJJ);

{удалили пробел в начале}

Л:;= length(st);

 

 

 

ifst[kj=

^^^ then delete(st,kj);

{удалили пробел в конце}

WriteLn('Результат:');

 

iflength(st.)<>0 then

WnteLn(st)

else WriteLn('Строка codepjfcana только пробелы.'); End

118

4. Структурные типы данных

Пример 4Л5. Разработать программу, которая вводит строки, содержа­ щие фамилию, имя, отчество и год рождения, а выводит - строки, содержа­ щие фамилию, инициалы и возраст на текущий год. Например:

Иванов Иван Иванович 1956 => Иванов И.И. 45

Завершение ввода - при чтении пустой строки.

Для выполнения операций над строками используем строковые функ­ ции. Обработку строк будем выполнять в цикле до ввода пустой строки. Нач­ нем с определения местоположения первого пробела, который отделяет имя от фамилии. Для этого используем функцию Pos, а результат запишем в пе­ ременную с1. Затем перепишем в строку результата фамилию, пробел и пер­ вый инициал. Туда же дописываем точ!^.

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

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

Несколько первых шагов преобразования показаны на рис. 4.29.

Program stroka;

Var st,strez,strab:string[40]:

cl, c2,c3,n, old,code:word;

cl

[T|

ИсходнаястрокаSt T""^

| и | в | а | н |

| и | в | а [ н [)(| в | и | ч |

| 1 | 9 | 5 | б |

1И|в 1 a 1HI 01 в 1

^

 

с2

 

 

 

 

 

 

Рабочая строка

1 4 1

 

 

strab

^

' '

 

 

| в | а | н |

 

| и | в | а | н | () РвУи|чУ

1 1 ] 9] 5 |Т]

г

1 1

 

""^^

 

Строка резулbxaxastrez

j ^

 

 

 

| И | в | а | н | о | в |

\Щ.\2кШЖЁШ^ t ] 1 1 1 1 1 II

Рис. 4.29. Начало решения задачи преобразования строк

119

Часть I. Основы алгоритмизации и процедурное программирование

Begin

WriteLn('Введите строку. Завершение - ввод пустой строки.'); ReadLn(st);

while sto^^ do {цикл ввода, преобразования и вывода строк} begin

cl:=Pos(' ',^/у);{определим местоположение первого пробела} strez:=Copy(stJ,c] + lJ+ \ V {перепишем фамилию, инициал

strab:=Copy(st,cl+2,Length(st)-cJ-l);

и добавим точку}

{копируем остаток строки

c2:=Pos(' \strab);

 

в рабочее поле}

{определяем местоположение второго пробела}

strez:=strez+strabfc2+lj+ \ V {добавляем к результату второй

Delete(strabJ,c2+l);

 

инициал и точку}

{удаляем распознанную часть}

c3:=PosC \strab); {onpmQ^HQM местоположение третьего пробела}

Delete(strabJ,c3);

{удаляем остаток имени}

Val(strab,n,code);

{преобразуем год рождения в число}

old:=2001'n;

{определяем возраст}

Str(old,strab);

{преобразуем возраст в строку}

strez:=strez-^ ' '+strab;

{добавляем возраст в результат}

WriteLn(strez);

{выводим результат}

WriteLnCВведите строку. Завершениеввод пустой строки. '); ReadLn(st);

end;

End.

4.6.Практикум. Обработка и поиск символьной информации

Воснове обработки символьной информации, как правило, лежит разби­ ение текста на слова и выполнение некоторых операций со словами.

Пример 4.16. Разработать программу, которая определяет в строке коли­ чество слов длиннее четырех символов. Слова разделены одним пробелом.

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

Program strokal; Var St: string;

p, spos:integer;

120