
- •2.7. Процедуры и функции
- •2.8. Рекурсия
- •2.9. Списки
- •2.10. Очереди и стеки
- •Создание (очистка) очереди
- •Проверка очереди на пустоту
- •Включение элемента в очередь
- •Выбор элемента из очереди
- •Создание (очистка) стека
- •Проверка стека на пустоту
- •Занесение элемента в стек
- •Выбор элемента из стека
- •2.11. Двоичные деревья
- •3. Заключение
- •3.1. Стандартизация стиля кодирования
- •3.2. Отладка программ
- •Список литературы
Создание (очистка) стека
Для создания нового пустого или очистки существующего стека достаточно присвоить указателю на первый его элемент (вершину) значение nil.
procedure CreateStack ( var StackHead: Stack);
begin
StackHead:= nil
end;
Проверка стека на пустоту
Условием пустоты стека является значение его вершины, равное nil.
function StackIsClear( var StackHead: Stack ): Boolean;
begin
StackIsClear:= ( StackHead= nil )
end;
Занесение элемента в стек
Для включения элемента в стек, необходимо создать новый элемент типа стек, затем инициализировать его информационное поле. В заключение изменить его указатель и указатель на первый элемент стека так, чтобы первым стал новый элемент.
procedure IncludeInStack( var StackHead: Stack; NewElem: TypeOfElem );
var
ServiceVar: Stack;
begin
{создание нового элемента}
new( ServiceVar );
ServiceVar^.Elem:= NewElem;
{созданный элемент сделать вершиной стека}
ServiceVar^.NextElem:= StackHead;
StackHead:= ServiceVar
end;
Выбор элемента из стека
При выполнении этой операции информационное поле элемента, находящегося в вершине стека, должно быть присвоено в качестве значения некоторой переменой, а сам элемент должен быть исключен из стека и уничтожен.
procedure SelectFromStack( var StackHead: Stack; var Result: TypeOfElem );
var
ServiceVar: Assoc;
begin
if StackHead <> nil then begin
{выбор элемента из вершины}
Result:= StackHead^.Elem;
{запоминание ссылки на старую вершину}
ServiceVar:= StackHead;
{исключение из стека и уничтожение элемента}
StackHead:= StackHead^.NextElem;
dispose( ServiceVar )
end
end;
Необходимо обратить внимание на введение вспомогательной переменной ссылочного типа ServiceVar для осуществления удаления элемента. Типична ошибка, связанная с попыткой решить эту задачу через dispose( StackHead ).
Разберем решение типичной задачи, связанной с обработкой стека.
Текст задания
Используя стек (считать уже описанными тип Stack с информационным элементом типа Char, функцию StackIsClear (проверка пустоты стека) и процедуры CreateStack (очистка стека), IncludeInStack (вставка элемента в стек), SelectFromStack (выборка элемента из стека)) решить следующую задачу: в текстовом файле f записана без ошибок формула следующего вида:
<формула>::= <цифра>|M(<формула>,<формула>)|m(<формула>,<формула>)
цифра::= 0|1|2|3|4|5|6|7|8|9
где M обозначает функцию max, а m – min. Вычислить (как целое число) значение данной формулы (например, M( 5, m( 6, 8)): 6).
Решение
program StackSample;
type
FileType= File of Char;
var
Source: FileType;
function formula( var t: FileType ): integer;
type
TypeOfElem= Char;
Assoc= ^ElementOfStack;
ElementOfStack= record
Elem: TypeOfElem;
NextElem: Pointer
end;
Stack= Assoc;
var
S: Stack;
c, op, x, y: char;
procedure CreateStack ( var StackHead: Stack);
begin
StackHead:= nil
end;
function StackIsClear( var StackHead: Stack ): Boolean;
begin
StackIsClear:= ( StackHead= nil )
end;
procedure IncludeInStack( var StackHead: Stack; NewElem: TypeOfElem );
var
ServiceVar: Stack;
begin
{создание нового элемента}
new( ServiceVar );
ServiceVar^.Elem:= NewElem;
{созданный элемент сделать вершиной стека}
ServiceVar^.NextElem:= StackHead;
StackHead:= ServiceVar
end;
procedure SelectFromStack( var StackHead: Stack; var Result: TypeOfElem );
var
ServiceVar: Assoc;
begin
if StackHead <> nil then begin
{выбор элемента из вершины}
Result:= StackHead^.Elem;
{запоминание ссылки на старую вершину}
ServiceVar:= StackHead;
{исключение из стека и уничтожение элемента}
StackHead:= StackHead^.NextElem;
dispose( ServiceVar )
end
end;
begin
reset( t );
CreateStack( S );
while not eof( t ) do begin
read(t, c);
{обработка очередной литеры текста (литеры «(» и «,» игнорируются)}
if c in ['0'..'9','M','m'] then IncludeInStack( S, c)
else
if c= ')' then begin {конец формулы вида op(x, y)}
{в конце стека находится тройка op x y, она удаляется
из стека, выполняется операция op и результат
записывается в стек}
SelectFromStack( S, y );
SelectFromStack( S, x );
SelectFromStack( S, op );
case op of
'M'{max}: if x > y then c:= x else c:= y;
'm'{min}: if x < y then c:= x else c:= y
end;
IncludeInStack( S, c )
end
end; {of while}
{в стеке осталась одна цифра – значение всей формулы; цифра переводится в целое число}
SelectFromStack( S, c );
formula:= ord( c ) - ord( '0' )
end;
begin
assign( Source, 'c:\temp\source.txt' );
writeln( Formula( Source ) );
end.
Варианты заданий
1. Очереди
Type FR= file of real; За один просмотр файла f типа FR и без использования дополнительных файлов вывести элементы файла f в следующем порядке: сначала- все числа, меньшие a, затем- все остальные числа, сохраняя исходный взаимный порядок в каждой из этих трех групп чисел (a заданное число).
Type FR= file of real; За один просмотр файла f типа FR и без использования дополнительных файлов вывести элементы файла f в следующем порядке: сначала все числа из отрезка [a, b], и затем - все остальные числа, сохраняя исходный взаимный порядок в каждой из этих трех групп чисел (a и b- заданные числа a < b).
Содержимое текстового файла f, разделенное на строки, переписать в текстовый файл g, перенося при этом в конец каждой строки все входящие в нее цифры (с сохранением исходного взаимного порядка, как среди цифр, так и среди остальных литер строки).
Содержимое текстового файла f, разделенное на строки, переписать в текстовый файл g, перенося при этом в конец каждой строки все входящие в нее строчные гласные латинского алфавита (с сохранением исходного взаимного порядка, как среди гласных, так и среди остальных литер строки).
Содержимое текстового файла f, разделенное на строки, переписать в текстовый файл g, перенося при этом в конец каждой строки все входящие в нее символы ‘+’, ‘-‘, ‘*’ (с сохранением исходного взаимного порядка как среди этих символов, так и среди остальных литер строки).
type name= (George, Alex, Piter, Ann, Paul, John, Fred, Natalie, Robert); child= array [name, name] of boolean; children= file of name; Считая заданными имя n и массив d типа child (d[x]= true, если человек по имени y является ребенком человека по имени x), записать файл p типа children имена всех потомков человека с именем n в следующем порядке: сначала – имена всех детей, затем – всех его внуков, затем – его правнуков и т.д.
Описать процедуру, которая по одной очереди строит две новых: Queue1 из положительных элементов и Queue2 - из остальных элементов очереди (TypeOfElem= real).
Описать процедуру, которая подсчитывает количество элементов очереди, у которых равные "соседи".
Описать процедуру, которая определяет, есть ли в очереди хотя бы один элемент, который равен следующему за ним элементу.
Описать процедуру, которая в очереди переставляет в обратном порядке все элементы между первыми последним вхождением элемента E, если E входит в L не менее двух раз.
Описать процедуру, которая удаляет из очереди первый отрицательный элемент, если такой есть.
Описать процедуру, которая из очереди, содержащего не менее двух элементов, удаляет все элементы, у которых одинаковые "соседи".
Описать процедуру, которая формирует очередь Queue, включив в нее по одному разу элементы, которые входят хотя бы в одну из очередей Queue1 или Queue2.
Описать процедуру, которая формирует очередь Queue, включив в нее по одному разу элементы, которые входят в очередь Queue1, но не входят в очередь Queue2.
Описать процедуру, которая формирует очередь Queue, включив в нее по одному разу элементы, которые входят в одну из очередей Queue1 и Queue2, но в то же время не входят в другую из них.
2. Стеки
Вывести содержимое текстового файла t, выписывая литеры каждой его строки в обратном порядке.
Проверить, является ли содержимое текстового файла t правильной записью формулы следующего вида
<формула>::= <терм> | <терм> + <формула> | <терм> - <формула>
<терм>::= <имя> | (<формула>) | [<формула>] | {<формула>}
<имя>::= x | y | z
В текстовом файле Log записано без ошибок логическое выражение (ЛВ) в следующей форме.
<ЛВ>::= true | false | ( <ЛВ>) | (<ЛВ> <ЛВ>) | (<ЛВ> <ЛВ>),
где знаки , и обозначают соответственно отрицание, конъюнкцию и дизъюнкцию. Вычислить (как boolean) значение этого выражения.
В текстовом файле t записан текст, сбалансированный по круглым скобкам:
<текст>::= <пусто> | <элемент> <текст>
<элемент>::= <буква> | (<текст>)
Требуется для каждой пары соответствующих открывающей и закрывающей скобок вывести номера их позиций в тексте, упорядочив пары номеров в порядке возрастания номеров этих позиций закрывающих скобок.
Для задачи 19 вывести номера их позиций в тексте, упорядочив пары номеров в порядке возрастания номеров этих позиций открывающих скобок.
Под «выражением» будем понимать конструкцию следующего вида.
<текст>::= <терм> | <терм> <знак+–> <выражение>
<знак+–>::= + | –
<терм>::= <множитель> | <множитель>*<терм>
<множитель>::= <число> | <переменная> | (<выражение>) | <множитель>^<число>
<число>::= <цифра>
<переменная>::= <буква>
Где знак ^ обозначает возведение в степень. Постфиксной формой записи выражения ab называется запись, в которой знак операции размещен за операндами: ab.
Описать функцию value( postfix ), которая вычисляет как целое число значение выражения (без переменных), записанного в постфиксной форме в текстовом файле postfix. Использовать следующий алгоритм вычисления. Выражение просматривается слева направо. Если встречается операнд (число), то его значение (как целое) заносится в стек, а если встречается знак операции, то из стека извлекаются два последних элемента (это операнды данной операции), над ними выполняется операция и ее результат записывается в стек. В конце концов, в стеке останется только одно число – значение всего выражения.
Описать процедуру translate( infix, postfix ), которая переводит выражение, записанное в обычной (инфиксной) форме в текстовом файле infix, в постфиксную форму и в таком виде записывает его в текстовый файл postfix. Использовать следующий алгоритм перевода. В стек записывается открывающая скобка, и выражение просматривается слева направо. Если встречается операнд (число или переменная), то он сразу переносится в файл postfix. Если встречается открывающая скобка, то она заносится в стек, а если встречается закрывающая скобка, то из стека извлекаются находящиеся там знаки операций до ближайшей открывающей скобки, которая также удаляется из стека, и все эти знаки (в порядке их извлечения) записываются в файл postfix. Когда встречается знак операции, то из стека извлекаются (до ближайшей скобки, которая сохраняется в стеке) знаки операций, старшинство которых больше или равно старшинству данной операции, и они записываются в файл postfix, после чего рассматриваемый знак заносится в стек. В заключение выполняются такие действия, как если бы встретилась закрывающая скобка.
Описать нерекурсивную процедуру infixprint( postfix ), которая печатает в обычной (инфиксной) форме выражение, записанное в постфиксной форме в текстовом файле postfix. (Лишние скобки желательно не печатать.)
Описать процедуру, которая по одному стеку строит два новых: Stack1 из положительных элементов и Stack2 - из остальных элементов (TypeOfElem= real).
Описать процедуру, которая подсчитывает количество элементов стека, у которых равные "соседи".
Описать процедуру, которая определяет, есть ли в стеке хотя бы один элемент, который равен следующему за ним элементу.
Описать процедуру, которая удаляет из стека первый отрицательный элемент, если такой есть.
Описать процедуру, которая формирует стек Stack, включив в него по одному разу элементы, которые входят хотя бы в один из стеков Stack1 или Stack2.
Описать процедуру, которая формирует стек Stack, включив в него по одному разу элементы, которые входят в стек Stack1, но не входят в стек Stack2.
Описать процедуру, которая формирует стек Stack, включив в него по одному разу элементы, которые входят в один из стеков Stack1 и Stack2, но в то же время не входят в другой из них.