Решение задач при помощи структур данных (стеки, очереди)

Очередь (queue) и стеки; структура данных, обработка (удаление) её элементов и порядок их поступления (добавления). Массивы и переменные указатели, реализация очереди с помощью массива, операции над очередями и их реализация, усовершенствования процедур.

Рубрика Программирование, компьютеры и кибернетика
Вид реферат
Язык русский
Дата добавления 12.12.2009
Размер файла 73,4 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

2

Лицей №1

«Решение задач при помощи структур данных (стеки, очереди)»

Выполнила Майдобурова С.А.

Барановичи

2004 г.

Введение

Структуры данных стеки и очереди используются для решения задач в курсе 10 - 11 класса с углубленным изучением информатики. Во-первых, в отличие от базового курса информатики, здесь все задачи решаются через блочную структуру программ, с использованием разработанных процедур и функций (а для этого нужно хорошо понимать, как их правильно написать). Во-вторых, многие олимпиадные задачи можно решать, используя эти структуры данных (в частности задача про «нулевые зоны» часто появляется на олимпиадах городского уровня). При этом логика реализации такой программы достаточно понятна ученикам и служит подготовкой для перехода к реализации решения этих же задач не с помощью массивов, а с помощью типа указатель. Учащиеся, усвоившие логику работы с такими структурами данных практически не испытывают никаких затруднений, изучая программирование на первых курсах ВУЗов, где есть такой предмет.

Очереди

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

в очередь из очереди

Есть несколько способов реализации такой структуры. Простейшей является реализация при помощи массива и двух переменных-указателей, один из которых определяет то место массива, куда элемент будет добавляться, и называется концом очереди (УК), а другой - определяет то место массива, откуда элемент будет удаляться, и называется началом очереди (УН). Если УК<>УН, то в очереди есть элементы, при этом элемент с меньшим номером считается поступившим в очередь раньше, чем элемент с большим номером.

Допустим, в очередь помещён элемент А, потом В, потом С. Тогда очередь имеет вид:

УН УК

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

УН УК

Теперь первым элементом в очереди будет В, а последним - С. Удаление происходит путём перемещения указателя УН, при этом элемент А остаётся в массиве (но не в очереди).

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

УН УК

Если нужно будет удалить какой-нибудь средний элемент очереди (например, С), сначала нужно удалить элементы, идущие до него (элемент В).

Из-за этого структуру очередь называют ещё структурой FIFO (First In, First Out) - «первым пришёл, первым ушёл».

Очередь, где нет ни одного элемента, называют пустой. В этом случае УК=УН.

Реализация очереди с помощью массива.

Операции над очередями и их реализация.

В программе для реализации структуры очередь будем использовать массив Q. В качестве указателя УН возьмём переменную n, а в качестве УК - переменную k. В самом начале переменным n и k присваивается значение 1. Условие n=k говорит о том, что очередь пуста.

Для работы с очередью определим четыре элементарные операции:

Pusto - создаёт пустую очередь.

Proverka - возвращает значение true, если очередь пуста, и false в противном случае.

Dobav - добавляет элемент в конец очереди.

Udalen - удаляет элемент из начала очереди.

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

1. Т.к. будет использоваться массив, то в переменную max лучше описать в разделе констант (задать её значение).

2. В разделе type сделать запись

Q = array [1..max] of real;

3. Затем создадим пустую очередь, выполнив процедуру Pusto.

Procedure Pusto (var a:Q; var n,k:integer);

Begin

n: =1;

k: =1;

End;

4. Операция Proverka используется для проверки очереди на «пустоту».

Function Proverka (var p:Q; var n,k:integer):Boolean;

Begin

if n = k then Proverka: = true else Proverka: = false;

End;

5. Операция Dobav может быть выполнена всегда, кроме случая, когда очередь уже полна. Поэтому, прежде чем вставить элемент в очередь, необходимо проверить массив на наличие свободного места. Значит, нам понадобится переменная с, значение которой будет равно 0, если операция добавления элемента не выполнена из-за отсутствия места в очереди, и равно 1 - если операция добавления прошла успешно.

Procedure Dobav (var p:Q; var n,k:integer; var c:integer; x:real);

Begin

if k>max then begin c: = 0; exit; end

else begin p[k]: = x; k: = k +1; c: = 1; end;

6. Операция удаления элемента из очереди Udalen может выполняться в том случае, если очередь не пуста. Поэтому сначала нужно убедиться, что очередь не пуста, и только потом можно удалять элемент из очереди. Значение переменной с будет равно 2, что означает, что операция удаления элементов невозможна из-за отсутствия таковых.

Procedure Udalen (var p:Q; var n,k:integer; var c:integer; x:real);

Begin

if Pusto(p,n,k) then begin c: = 2; exit; end

else begin x: = p[k]; n: = n + 1; c: = 1; end;

Замечания и некоторые возможные усовершенствования процедур.

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

Чтобы избежать такой ситуации, можно рассматривать кольцевую очередь. Для этого нужно обеспечить, чтобы в массиве после элемента с номером max следовал элемент с номером 1. Тогда возможна ситуация, когда УН>УК. А при УН=УК может быть две ситуации: когда очередь пуста и когда очередь полна. Значит, необходимо знать тип последней операции: было добавление или удаление элемента. Используем переменную Ор, значение которой будет равно 1 при добавлении элемента, и 0 - при удалении.

В таком случае, процедуры добавления и вставки элемента будут такими:

Procedure Dobav (var p:Q; var n,k:integer; var c,Op:integer; x:real);

Begin

if (Op = 1) and (n = k) then begin c: = 0; {Очередь полна}

exit;

end

else begin Op: = 1;

p[k]: = x;

k: = k + 1;

if k > max then begin k: = 1; c: = 1 end;

end;

End;

Procedure Udalen (var p:Q; var n,k:integer; var c,Op:integer; x:real);

Begin

if (Op = 0) and (n = k) then begin c: = 2; {Очередь пуста}

exit;

end

else begin Op: = 0;

x: = p[k];

n: = n + 1;

if n > max then begin n: = 1; c: = 1; end;

end;

End;

Решение задач с помощью очереди.

Пример 1.

Из листа клетчатой бумаги размером M x N удалили некоторые клетки размером 1 х 1. Определите, на сколько связных кусков распадается оставшаяся часть листа. К - количество удалённых клеток, (х1; у1), …, (хk; yk) - координаты удалённых клеток.

Для решения данной задачи рассмотрим двумерный массив M x N, где удалённые клетки имеют значение -1, а неудалённые - 0.

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

Далее выбираем новую начальную клетку и опять повторяем процесс нахождения её «соседей», равных 0.

Алгоритм закончится, когда на «листе» не останется клеток со значением 0.

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

Для примера рассмотрим лист размером 4 х 5, где удалёнными (со значением -1) считаются клетки с координатами (1;5), (4;5), (3;4), (2;3), (2;2), (1;1), (3;1). Итак,

i \ j

1

2

3

4

1

-1

0

-1

0

2

0

-1

0

0

3

0

-1

0

0

4

0

0

-1

0

5

-1

0

0

-1

Теперь найдём первую клетку со значением 0 и занесём её координаты в очередь. При этом в матрицу на соответствующее место ставится номер куска, который рассматривается (в данном случае 1). Первой найдена клетка с координатами (1;2).

Индексы

1

2

3

4

5

6

7

8

9

10

11

12

13

14

i

1

j

2

УН = УК

i \ j

1

2

3

4

1

-1

1

-1

0

2

0

-1

0

0

3

0

-1

0

0

4

0

0

-1

0

5

-1

0

0

-1

Рядом с этой клеткой нет других, со значением 0. Удаляем эту клетку из очереди, при этом УН становится опять равным УК. Потом ищем следующую начальную клетку. Это будет клетка с координатами (1;4). Её в таблице помечаем номером 2 (второй кусок). В очередь вносим её координаты и координаты её нулевых «соседей»-клеток, а потом их «соседей», и т.д. Получим следующее:

Индексы

1

2

3

4

5

6

7

8

9

10

11

12

13

14

i

1

1

2

2

3

3

3

4

j

2

4

4

3

4

3

4

4

УН = УК

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

Массив-лист примет следующий вид:

i \ j

1

2

3

4

1

-1

1

-1

2

2

0

-1

2

2

3

0

-1

2

2

4

0

0

-1

2

5

-1

0

0

-1

Следующий начальный нулевой элемент с координатами (2;1) будет уже помечаться номером 3 (третий кусок). Вносим его координаты в очередь, и действуем по знакомому алгоритму.

Индексы

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

i

1

1

2

2

3

3

3

4

2

2

3

4

4

5

5

j

2

4

4

3

4

3

4

4

3

1

1

1

2

2

3

УН=УК

Массив примет вид:

i \ j

1

2

3

4

1

-1

1

-1

2

2

3

-1

2

2

3

3

-1

2

2

4

3

3

-1

2

5

-1

3

3

-1

Больше нулевых элементов нет. Поэтому алгоритм будет завершен. Количество кусков равно 3.

Реализация алгоритма на языке Pascal.

Program Kuski;

uses crt;

const max = 100;

type

p = array[1..2,1..max] of byte;

var

m,n,i,j,x,y:integer;

w,c,d,l,k,s:integer;

a:array[1..10,1..10] of shortint;

q:p;

Procedure Pusto(var q:p;var c,d:integer);

begin

c:=1; d:=1;

end;

Function Prover(var q:p;var c,d:integer):boolean;

begin

if c=d then Prover:=true else Prover:=false;

End;

Procedure Dobav(var q:p;var c,d:integer; var s:integer;

var a,b:integer);

begin

if d>max then begin s:=0; exit; end;

q[1,d]:=a; q[2,d]:=b;

d:=d+1;

s:=1;

End;

Procedure Udalen(var q:p;var c,d:integer; var s:integer);

begin

if Prover(q,c,d) then begin s:=0; exit; end;

c:=c+1;

s:=2;

End;

BEGIN clrscr;

write('m='); readln(m);

write('n='); readln(n);

for i:=1 to m do

for j:=1 to n do begin

write('a[',i,',',j,']=');

readln(a[i,j]); end;

Pusto(q,c,d);

k:=0;

for i:=1 to m do

for j:=1 to n do

if a[i,j]=0 then begin

k:=k+1;

Dobav(q,c,d,s,i,j);

a[i,j]:=k;

while c<>d do

for l:=c to d do begin

x:=q[1,l]; y:=q[2,l];

if (x>1) and (a[x-1,y]=0) then begin w:=x-1; Dobav(q,c,d,s,w,y);

a[w,y]:=k;

end;

if (x<m) and (a[x+1,y]=0) then begin w:=x+1;

Dobav(q,c,d,s,w,y);

a[x+1,y]:=k;

end;

if (y>1) and (a[x,y-1]=0) then begin w:=y-1;

Dobav(q,c,d,s,x,w);

a[x,y-1]:=k;

end;

if (y<n) and (a[x,y+1]=0) then begin w:=y+1;

Dobav(q,c,d,s,x,w);

a[x,y+1]:=k;

end;

Udalen(q,c,d,s);

end;

end;

writeln('Количество кусков k=',k);

readln;

END.

Пример 2.

Имеется план местности, разбитой на квадраты, заданный матрицей размером M x N. Каждый квадрат имеет одно из обозначений: 0, если в квадрате твёрдая почва, и -1, если в квадрате болото. Необходимо определить, имеется ли в маршрут робота из позиции (ХС, УС) в позицию (ХФ, УФ), если робот может двигаться только по ровной местности и только в горизонтальном и вертикальном направлениях. При этом вдоль границ квадратов двигаться нельзя.

Решение задачи похоже на решение предыдущей с несколькими отличиями:

1) нам не нужно больше искать все куски по которым ходит робот, перемещаться нужно будет только в пределах одного куска;

2) необходимо сделать проверку исходной точки - старта робота, и конечной - финиша, не являются ли они координатами болота. Если это так - нет смысла искать маршрут.

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

program Robot;

uses crt;

const max=100;

type p=array[1..3,1..max] of byte;

var

m,n,i,j,x,y,z,nx,ny,kx,ky:integer;

w,c,d,l,k,s,h:integer;

a:array[1..10,1..10] of shortint;

q,v:p;

Procedure Pusto(var q:p;var c,d:integer);

begin

c:=1;

d:=1;

End;

Function Prover(var q:p;var c,d:integer):boolean;

begin

if c=d then Prover:=true else Prover:=false;

End;

Procedure Dobav(var q:p;var c,d:integer; var s:integer;

var a,b:integer;var k:integer);

begin

if d>max then begin s:=0; exit; end;

q[1,d]:=a;

q[2,d]:=b;

q[3,d]:=k;

d:=d+1;

s:=1;

End;

Procedure Udalen(var q:p;var c,d:integer; var s:integer);

begin

if Prover(q,c,d) then begin s:=0; exit; end;

c:=c+1; s:=2;

End;

BEGIN

clrscr;

write('m='); readln(m);

write('n='); readln(n);

writeln('Введите значения клеток');

for i:=1 to m do

for j:=1 to n do begin

write('a[',i,',',j,']=');

readln(a[i,j]); end;

write('nx=');readln(nx);

write('ny=');readln(ny);

if a[nx,ny]=-1 then begin writeln('Робот не будет начинать свой путь в болоте!!!'); readln; exit; end;

write('kx=');readln(kx);

write('ky=');readln(ky);

if a[kx,ky]=-1 then begin writeln('Робот не должен заканчивать свой путь в болоте!!!'); readln; exit; end;

Pusto(q,c,d);

k:=1;

Dobav(q,c,d,s,nx,ny,k);

a[nx,ny]:=k;

while c<>d do

for i:=c to d do begin

x:=q[1,i];

y:=q[2,i];

h:=q[3,i];

if (x>1) and (a[x-1,y]=0) then begin w:=x-1; k:=h+1;

Dobav(q,c,d,s,w,y,k);

a[w,y]:=k;

end;

if (x<m) and (a[x+1,y]=0) then begin w:=x+1; k:=h+1;

Dobav(q,c,d,s,w,y,k);

a[x+1,y]:=k;

end;

if (y>1) and (a[x,y-1]=0) then begin w:=y-1; k:=h+1;

Dobav(q,c,d,s,x,w,k);

a[x,y-1]:=k;

end;

if (y<n) and (a[x,y+1]=0) then begin w:=y+1; k:=h+1;

Dobav(q,c,d,s,x,w,k);

a[x,y+1]:=k;

end;

Udalen(q,c,d,s);

end;

{ writeln('k=',k); }

for i:=1 to 3 do begin

for j:=1 to d-1 do

write(q[i,j]:3);

writeln;

end;

writeln;

h:=0;

for j:=1 to d-1 do

if (q[1,j]=kx) and (q[2,j]=ky) then begin h:=j; k:=q[3,j]; end;

if h<>0 then begin

writeln('Путь пройден за ',k-1,' шаг(-ов)!');

v[1,k]:=q[1,h];

v[2,k]:=q[2,h];

v[3,k]:=q[3,h];

i:=k;

for j:=h-1 downto 1 do begin

x:=q[1,j];

y:=q[2,j];

z:=q[3,j];

if (v[3,i]-z=1) and (((abs(x-v[1,i])=1) and (y=v[2,i])) or ((x=v[1,i]) and (abs(y-v[2,i])=1)))

then begin i:=i-1;

v[1,i]:=x;

v[2,i]:=y;

v[3,i]:=z;

end; end;

for i:=1 to 2 do ?????

for j:=1 to k do

write(v[i,j]:3);

writeln;

????

end

else writeln('Такого пути нет!');

readln;

END.

Стеки.

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

Помещение в стек в порядке: A, B, C, D, E, F.

Извлечение из стека в порядке: F, E, D, C, B, A.

Итак, стек - это такая последовательность данных, доступ к элементам которой осуществляется только с одного конца. Этот элемент традиционно находится сверху и это место называется вершиной стека vs.

Стек часто обозначают аббревиатурой LIFO (Last In, First Out) - «последний пришёл, первый ушёл», а для его моделирования с помощью массива достаточно одного указателя.

Вопросы «на закуску»:

1. Можете ли вы привести примеры стека из повседневной жизни.

2. Сколько необходимо указателей для стека?

3. Что определяет указатель стека?

Операции над стеками.

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

Для стека определены 4 элементарные операции:

1) эта процедура создаёт пустой стек; указательvs приравниваем к 0, в стеке s ещё ничего не записано:

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

2) эта функция возвращает значение true, если стек пуст и false в обратном случае:

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

3) при помощи этой процедуры добавляем элемент в стек; в случае успешного добавления переменная с = 1, неудачи (массив заполнен до отказа, т.е. vs = max) - с=0:

Procedure Dobav(var s:stack;var vs:integer; var c:integer; var x:integer);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[vs]:=x;

c:=1;

End;

4) эта процедура удаляет элемент из стека; в случае удачного удаления переменная с = 2, неудачи (массив пуст - удалять нечего!) - с = 0:

Procedure Udal(var s:stack;var vs:integer; var c:integer; var x:integer);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[vs];

vs:=vs-1;

c:=2;

End;

Решение задач при помощи стека.

Пример 1.

Рассмотрим математическое выражение, в котором имеется несколько уровней вложенных круглых скобок, например

7 - ((Х * ((Х + Y) / (J - 3)) + Y) / (4 - 2,5)).

Убедиться, что скобки расставлены правильно.

Решение:

Скобки расставлены правильно, если 1) КОЛ-ВО `(` = КОЛ-ВО `)`.

2) Каждой скобке `(` соответствует своя `)`.

Например, первое условие нарушено в выражении: (A - (B + C) - D / (A + C),

а второе условие нарушено в выражении: (A - B) + C) - (D / (A + C).

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

program Skobki;

var

s:string;

i,k:byte;

BEGIN

writeln(`Введите арифметическое выражение со скобками');

readln(s);

k:=0; {количество скобок}

i:=1; {порядковый номер рассматриваемого символа строки арифм. выражения}

while (i<=length(s)) and (k>0) do begin

if s[i]='(' then k:=k+1

else if s[i]=')' then k:=k-1;

i:=i+1;

end;

if (k=0)and(i=length(s)+1) then writeln(`Скобки расставлены верно')

else writeln(`Скобки расставлены неверно');

readln;

END.

Пример 2.

Допустим, что в математическом выражении встречаются скобки трёх типов: круглые «(«, «)», квадратные «[», «]» и фигурные «{», «}». Необходимо проверить, выполняется ли баланс скобок, учитывая, что закрывающаяся скобка должна быть того же типа, что и предшествующая ей открывающаяся.

Пример неправильного выражения: (A - [B + C ] }- D / {A + C).

Задача усложнена, по сравнению с предыдущей, из-за типов скобок.

Алгоритм наших действий тогда будет таким: ПОКА СТРОКА НЕ ЗАКОНЧИЛАСЬ - ДЕЛАЙ:

Рассмотрим действие этих команд на примере:

{x+(y-[a+b])*c-[(d+e)]}/(h-(j-(k-[1-n]))).

]

]

)

[

)

(

[

)

(

]

(

(

(

)

{

{

(

(

[

[

[

}

(

(

(

(

(

{

{

{

{

{

{

(

(

(

(

(

(

а)

б)

в)

г)

д)

е)

ж)

з)

и)

к)

л)

м)

н)

о)

р)

Реализация программы на Pascal:

program Skobki;

const

max=20;

type

stack=array[1..max] of char;

var

x:char;

p:string;

s:stack;

d,i,c,vs:integer;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer; var x:char);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[vs]:=x;

c:=1;

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer; var x:char);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[vs];

vs:=vs-1;

c:=0;

End;

BEGIN

Pusto(s,vs);

writeln('Введите арифметическое выражение с разными типами скобок');

readln(p);

d:=length(p);

i:=1;

while i<=d do

begin

x:=p[i];

case x of

'(','[','{': Dobav(s,vs,c,x);

')':if (vs-1>=0) and (s[vs]='(') then Udal(s,vs,c,x)

else begin writeln('Ошибка'); readln; exit end;

']':if (vs-1>=0) and (s[vs]='[') then Udal(s,vs,c,x)

else begin writeln(' Ошибка '); readln; exit end;

'}':if (vs-1>=0) and (s[vs]='{') then Udal(s,vs,c,x)

else begin writeln(' Ошибка '); readln; exit end;

end;

i:=i+1;

end;

if vs<>0 then writeln(' Ошибка ')

else writeln('Выражение составлено правильно');

readln;

End.

Перед рассмотрением третьего примера, следует сказать, что существует несколько способов записи арифметических выражений. Пусть для операндов А и В выполняется сложение. Мы привыкли это записывать в виде: А+В. Такая форма записи называется инфиксной (наверное, подразумевается что приставочка «ин-» говорит о расположении знака внутри). А ещё существуют префиксная(+АВ) и постфиксная(АВ+) формы записи. Отличают они друг от друга положением знака операции по отношению к операндам. Потренируемся в переходах от одной формы записи к другой.

Пусть дано выражение А + В * С. Умножение имеет высший приоритет, чем сложение, поэтому не будет ошибкой (выражение не изменится), если запишется так: А + (В * С). Для записи постфиксного выражения преобразуем сначала ту часть выражения, которая вычисляется первой: А + (ВС *). Осталось записать в постфиксной форме операцию сложения между операндами А и (ВС *): А(ВС*)+ или же АВС * +.

Порядок преобразования в префиксную форму (без комментариев, т.к. аналогично):

1) А + (В * С)

2) А + (* ВС)

3) + А(*ВС)

4) + * АВС

Ещё потренируемся. Дано выражение: (А + В) * С. В постфиксной форме:

(АВ +) * С; (АВ +) С *; АВ + С *.

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

Инфиксная форма

Префиксная форма

Постфиксная форма

А + В

+ AB

AB +

А + В - С

- + ABC

AB + C -

(А + В) * (С - D)

* + AB - CD

AB + CD - *

A ^ B * C - D + E / F / (G + H)

+ - * ABCD / EF + GH

AB ^ C * D - EF / GH + / +

((A + B) * (D - E)) ^ (F + G)

^ * + AB - DE + FG

FB + DE - * FG + ^

A - B / (C * D ^ E)

- A / B * C ^ DE

ABCDE ^ * / -

Пример 3.

Пусть задано выражение a + b * c + (d * e + f) * g. Записать это выражение в постфиксной форме. (Для проверки, правильным ответом будет: abc * + de * f + g * +).

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

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

2) Если встретилась открывающаяся скобка, то помещаем её в стек.

3) Если встретилась закрывающаяся скобка, то выталкиваем из стека в строку все операторы до тех пор, пока из стека не появится открывающаяся скобка. Но ни открывающуюся, ни закрывающуюся скобку в строку помещать не надо.

4) Если нам встретился оператор (арифметический знак), то из стека следует вытолкнуть все операторы, приоритет которых не выше (ниже или такой же) нашего оператора. После этого в стек записываем наш оператор. (Написано туманно, но далее следует пример, где всё станет понятным).

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

Рассмотрим пошагово, что и как должно происходить.

Итак, дана строка р = «a + b * c + (d * e + f) * g». Заведём строку v, куда будем помещать результирующее выражение. Стек - s.

Первый символ - а. Это операнд, помещаем его в строку v.

Далее идёт «+». Это оператор, помещаем его в стек s под номером 1.

Следующий символ - b. Это операнд, он попадает в строку v.

На данный момент ситуация такая:

Стек s

Строка v

+

ab

Следующий символ «*». Это оператор. Элемент в вершине стека имеет более низкий приоритет, чем «*», поэтому в строку v ничего не помещаем, а «*» помещаем в стек.

Далее идёт символ с. Поместим его в строку v.

Теперь ситуация такая:

Стек s

Строка v

*

+

abс

Потом встречаем символ «+». Это оператор. Но в вершине стека находится «*», у которой более высокий приоритет. Поэтому извлекаем этот элемент из стека и помещаем в строку v (“abc*”). Следующий элемент стека «+». Он имеет тот же приоритет, что и текущий символ строки v. Следовательно, тоже извлекаем его из стека и помещаем в строку v. А текущий «+» помещаем в стек. В итоге:

Стек s

Строка v

+

abс*+

В данной нам строке следующим символом будет «(«. У него самый высокий приоритет, помещаем его в стек.

За ним следует символ d; это операнд, который мы поместим в строку v.

Стек s

Строка v

)

+

abс*+d

Потом добираемся до символа «*». Открывающаяся скобка имеет высший приоритет, поэтому из стека её извлечь нельзя до того, как мы встретим закрывающуюся скобку. Значит, «*» просто помещаем в стек.

За ним следует символ е. Этот операнд помещается в строку v. На этом этапе:

Стек s

Строка v

*

(

+

abс*+de

Следующий прочитанный символ «+». Элемент стека «*» имеет более высокий приоритет, значит извлекаем его из стека в выходную строку, а символ «+» помещаем в стек.

На очереди символ f. Его поместим в строку v.

Стек s

Строка v

+

(

+

abс*+de*f

А вот теперь мы встречаем закрывающуюся скобку. В этом случае все элементы стека до «(« включительно помещаем в строку v. Но символ «(« туда не попадает, он просто игнорируется (свою роль он уже сыграл).

Стек s

Строка v

+

abc*+de*f+

Читаем символ «*», он попадает в стек.

Следующий символ g - отправляем в строку v.

Стек s

Строка v

*

+

abc*+de*f+g

Строка, из которой мы читали символы, исчерпана. Значит, осталось извлечь в выходную строку все символы. Результат наших действий:

Стек s

Строка v

abc*+de*f+g*+

А теперь реализация этих действий на языке Pascal:

program Vyrazhenie;

const

max=10;

type

stack=array[1..2,1..max] of string[5];

var

t,x,y,z,e,p,v:string;

s:stack;

w,i,d,f,c,vs:integer;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer; var x,z:string);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[1,vs]:=x;

s[2,vs]:=z;

c:=1;

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer; var x,z:string);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[1,vs];

z:=s[2,vs];

vs:=vs-1;

c:=0;

End;

BEGIN

writeln('Введите арифметическое выражение в инфиксной форме');

readln(p);

d:=length(p);

i:=1;

v:='';

t:='';

f:=5;

e:='';

while i<=d do begin

x:=p[i];

if x='(' then w:=1 else

if x=')' then w:=2 else

if (x='+') or (x='-') then w:=3 else

if (x='*') or (x='/') then w:=4 else w:=5;

case w of

1:begin

if (f=5) and (t<>'') then begin v:=v+t+' ';t:='';end;

e:='0';f:=1;

Dobav(s,vs,c,x,e);

end;

2:begin

if (f=5) and (t<>'') then begin v:=v+t+' ';t:='';end;

while s[1,vs]<>'(' do begin

Udal(s,vs,c,y,z);

v:=v+y+' ';

end;

Udal(s,vs,c,y,z);

e:='0'; f:=2;

end;

3:begin

if (f=5) and (t<>'') then begin v:=v+t+' ';t:=''; end;

e:='1'; f:=3;

while (s[2,vs]>=e) and (s[2,vs]<>'0') do

begin Udal(s,vs,c,y,z);

v:=v+y+' ';

end;

Dobav(s,vs,c,x,e);

end;

4:begin

if (f=5) and (t<>'') then begin v:=v+t+' ';t:='';end;

e:='2'; f:=4;

while (s[2,vs]>=e) and (s[2,vs]<>'0') do

begin

Udal(s,vs,c,y,z);

v:=v+y+' ';

end;

Dobav(s,vs,c,x,e);

end;

5:begin t:=t+x;f:=5;end;

else writeln('Mistake');

end;

i:=i+1;

end;

if t<>'' then v:=v+t+' ';

while vs<>0 do begin

Udal(s,vs,c,y,z);

v:=v+y+' '; end;

writeln(`В постфиксной форме выражение выглядит так: ',v);

readln;

End.

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

Решение:

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

Пусть задано выражение в постфиксной форме: А=”6523+8*+3+*”. Сначала организуем пустой стек. Первые четыре символа-цифры - это операнды, читаем и помещаем их в стек (Рис.1)

Следующий элемент «+». Извлекаем из стека «2» и «3», выполним действие 3+2, результат «5» помещаем в стек (Рис. 2)

Рис.3 Рис.4 Рис.5 Рис.6 Рис.7

Далее в стек помещаем число «8» (Рис.3)

Далее в строке идёт знак операции «*». Извлекаем из стека «8» и «5», выполняем действие 8*5, а результат «40» помещаем в стек (Рис. 4)

Следующим символом в исходной строке будет «+». Из стека забираем «40» и «5», выполняем 40+5, результат 45 помещаем в стек (Рис.5)

Читаем и помещаем в стек очередной операнд «3» (Рис.6)

Следующий символ входной строки «+». Поэтому извлекаем из стека операнды для этой операции («3» и «45»), выполняем сложение, результат «48» помещаем в стек (Рис. 7)

Последний символ - «*». Операндами для этой операции берём «48» и «6», выполняем умножение, результат «288» помещаем в стек. Значение заданного выражения найдено.

Реализация этого примера на Pascal:

program Poschitay;

const

max=10;

type

stack=array[1..max] of string[10];

var

p,t,x:string;

s:stack;

vs2,w,i,d,f,c,vs:integer;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer; var x:string);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[vs]:=x;

c:=1;

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer; var x:string);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[vs];

vs:=vs-1;

c:=2;

End;

procedure Deystvie(var s:stack; var vs2:integer);

var

q,r,z:string;

w,c,c1,c2:integer;

q1,r1:word;

Begin

if x='+' then w:=1 else

if x='-' then w:=2 else

if x='/' then w:=3 else

if x='*' then w:=4;

Udal(s,vs,c,q);Udal(s,vs,c,r);

val(q,q1,c1);val(r,r1,c1);

case w of

1:r1:=q1+r1;

2:r1:=r1-q1;

3:r1:=r1 div q1;

4:r1:=q1*r1;

end;

str(r1,x);

Dobav(s,vs,c2,x);

End;

BEGIN

writeln('Введите выражение в постфиксной форме');

readln(p);

d:=length(p);

i:=1;

while i<=d do begin

x:=p[i];

if (x='+') or (x='-') or (x='*') or (x='/') then Deystvie(s,vs)

else Dobav(s,vs,c,x);

i:=i+1; end;

writeln(s[vs]);

readln;

End.

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

Решение:

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

program Poschitay;

const

max=10;

type

stack=array[1..2,1..max] of string[10];

var

t,x,y,z,e,p,v:string;

st,s:stack;

vs2,w,i,d,c,vs:integer;

f:Boolean;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer; var x,z:string);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[1,vs]:=x;

s[2,vs]:=z;

c:=1;

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer; var x,z:string);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[1,vs];

z:=s[2,vs];

vs:=vs-1;

c:=0;

End;

procedure Deystvie(var s,st:stack; var vs:integer;var vs2:integer);

var

q,r,x,z:string;

w,c,c1,c2:integer;

q1,r1:real;

Begin

Udal(s,vs,c,x,z);

if x='+' then w:=1 else

if x='-' then w:=2 else

if x='/' then w:=3 else

if x='*' then w:=4;

Udal(st,vs2,c,q,z);Udal(st,vs2,c,r,z);

val(q,q1,c1);val(r,r1,c1);

case w of

1:r1:=q1+r1;

2:r1:=r1-q1;

3:r1:=r1/q1;

4:r1:=q1*r1;

end;

str(r1,x);

if w=3 then begin c2:=pos('.',x); delete(x,c2,1);Insert('.',x,c2-1); end;

Dobav(st,vs2,c2,x,z);

End;

BEGIN

writeln('Ввведите арифм. выражение с употреблением знаков +, -, *, /, скобок «(» и «)», цифр');

readln(p);

d:=length(p);

i:=1;

v:='';

t:='';

f:=true;

e:='';

while i<=d do begin

x:=p[i];

if x='(' then w:=1 else

if x=')' then w:=2 else

if (x='+') or (x='-') then w:=3 else

if (x='*') or (x='/') then w:=4 else w:=5;

case w of

1:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:='';end;

e:='0';f:=false;

Dobav(s,vs,c,x,e);

end;

2:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:='';end;

while s[1,vs]<>'(' do Deystvie(s,st,vs,vs2);

Udal(s,vs,c,y,z);

e:='0'; f:=false;

end;

3:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:=''; end;

e:='1'; f:= false;

while (s[2,vs]>=e) and (s[2,vs]<>'0') do

Deystvie(s,st,vs,vs2);

Dobav(s,vs,c,x,e);

end;

4:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:='';end;

e:='2'; f:= false;

while (s[2,vs]>=e) and (s[2,vs]<>'0') do Deystvie(s,st,vs,vs2);

Dobav(s,vs,c,x,e);

end;

5:begin t:=t+x;f:=true;end;

else writeln('Mistake');

end;

i:=i+1;

end;

if t<>'' then Dobav(st,vs2,c,t,e);

while vs<>0 do

Deystvie(s,st,vs,vs2);

writeln(st[1,vs2]);

readln;

End.

Пример 6.

Вычислить значение выражения, в котором могут участвовать знаки «+», «-», «/», «*», скобки «(» и «)», целые и дробные числа, причём десятичные записываются через знак «.», а обыкновенные дроби, к примеру, так: 7/12 или 5 1/3.

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

program Poschitay;

const

max=10;

type

stack=array[1..2,1..max] of string[10];

var

t,x,y,z,e,p,v:string;

st,s:stack;

vs2,w,i,d,c,vs:integer;

f:boolean;

procedure NOD(var a,b,c,d:longint);

begin

c:=a;

d:=b;

while a<>b do

if a>b then a:=a-b else b:=b-a;

c:=c div a;

d:=d div b;

end;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer; var x,z:string);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[1,vs]:=x;

s[2,vs]:=z;

c:=1;

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer; var x,z:string);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[1,vs];

z:=s[2,vs];

vs:=vs-1;

c:=0;

End;

procedure Chislo(var ch:string);

var

i,j,a,b,c:byte;

m,n,k:string;

m1,n1,k1:longint;

z:integer;

begin

a:=pos('.',ch);

b:=pos(' ',ch);

c:=pos('/',ch);

if (a=0) and (b=0) and (c=0) then ch:=ch+'/1'

else if a<>0 then begin Delete(ch,a,1);

a:=length(ch)+1-a;

while ch[1]='0' do

ch:=copy(ch,2,length(ch)-1);

ch:=ch+'/1';

for j:=1 to a do

ch:=ch+'0';

end

else if (b<>0) and (c<>0) then

begin

m:=copy(ch,1,b-1);

n:=copy(ch,b+1,c-b-1);

k:=copy(ch,c+1,length(ch)-c+1);

val(m,m1,z);

val(n,n1,z);

val(k,k1,z);

m1:=m1*k1+n1;

str(m1,ch);

ch:=ch+'/'+k;

end;

End;

procedure Summa(var x,y,z:string);

var

f:shortint;

k,l,m,n:string;

c:integer;

a,b:byte;

k1,k2,l1,m1,n1:longint;

begin

if (x='0') and (y<>'0') then z:=y else

if (y='0') and (x<>'0') then z:=x else

if (x='0') and (y='0') then z:='0' else

begin

a:=pos('/',x);

b:=pos('/',y);

k:=copy(x,1,a-1);

l:=copy(x,a+1,length(x)-a);

m:=copy(y,1,b-1);

n:=copy(y,b+1,length(y)-b);

val(k,k1,c);

val(l,l1,c);

val(m,m1,c);

val(n,n1,c);

k1:=k1*n1+l1*m1;

f:=0;

if k1=0 then z:='0' else begin

if k1<0 then f:=-1;

k2:=abs(k1);

l1:=l1*n1;

Nod(k2,l1,m1,n1);

str(m1,x);str(n1,y);

z:=x+'/'+y;

if f=-1 then z:='-'+z; end;

end;

End;

procedure Raznost(var x,y,z:string);

var

f:shortint;

k,l,m,n:string;

c:integer;

a,b:byte;

k1,k2,l1,m1,n1:longint;

begin

if (x='0') and (y<>'0') then z:=y else

if (y='0') and (x<>'0') then z:=x else

if (x='0') and (y='0') then z:='0' else

begin

a:=pos('/',x);

b:=pos('/',y);

k:=copy(x,1,a-1);

l:=copy(x,a+1,length(x)-a);

m:=copy(y,1,b-1);

n:=copy(y,b+1,length(y)-b);

val(k,k1,c);

val(l,l1,c);

val(m,m1,c);

val(n,n1,c);

k1:=k1*n1-l1*m1;

f:=0;

if k1=0 then z:='0' else begin

if k1<0 then f:=-1;

k2:=abs(k1);

l1:=l1*n1;

Nod(k2,l1,m1,n1);

str(m1,x);str(n1,y);

z:=x+'/'+y;

if f=-1 then z:='-'+z; end;

end;

End;

procedure Umn(var x,y,z:string);

var

f:shortint;

k,l,m,n:string;

c:integer;

a,b:byte;

k1,k2,l1,m1,n1:longint;

begin

if (x='0') or (y='0') then z:='0' else

begin

a:=pos('/',x);

b:=pos('/',y);

k:=copy(x,1,a-1);

l:=copy(x,a+1,length(x)-a);

m:=copy(y,1,b-1);

n:=copy(y,b+1,length(y)-b);

val(k,k1,c);

val(l,l1,c);

val(m,m1,c);

val(n,n1,c);

k1:=k1*m1;

l1:=l1*n1;

f:=0;

if k1<0 then f:=-1;

k2:=abs(k1);

Nod(k2,l1,m1,n1);

str(m1,x);str(n1,y);

z:=x+'/'+y;

if f=-1 then z:='-'+z;

end;

End;

procedure Delenie(var x,y,z:string);

var

f:shortint;

k,l,m,n:string;

c:integer;

a,b:byte;

k1,k2,l1,l2,m1,n1:longint;

begin

if x='0' then z:='0' else

if y='0' then begin writeln('Деление на 0!!!!!'); exit end

else begin

a:=pos('/',x);

b:=pos('/',y);

k:=copy(x,1,a-1);

l:=copy(x,a+1,length(x)-a);

m:=copy(y,1,b-1);

n:=copy(y,b+1,length(y)-b);

val(k,k1,c);

val(l,l1,c);

val(m,m1,c);

val(n,n1,c);

k1:=k1*n1;

l1:=l1*m1;

f:=1;

if k1<0 then f:=-1;

k2:=abs(k1);

if l1<0 then f:=f*(-1);

l2:=abs(l1);

Nod(k2,l2,m1,n1);

str(m1,x);str(n1,y);

z:=x+'/'+y;

if f=-1 then z:='-'+z;

end;

End;

procedure Cel_chast(var n,k:string);

var

f:shortint;

c:integer;

a,b:string[9];

p,a1,a2,b1,t,r:longint;

begin

p:=pos('/',n);

f:=0;

a:=copy(n,1,p-1); val(a,a1,c);

if a1<0 then f:=-1;

a2:=abs(a1);

b:=copy(n,p+1,length(n)-p); val(b,b1,c);

t:=a2 div b1;

r:=a2 mod b1;

if t=0 then k:='' else str(t,k);

if r<>0 then begin if k<>'' then k:=k+' ';

str(r,a); k:=k+a+'/'+b end;

if f=-1 then k:='-'+k;

end;

procedure Deystvie(var s,st:stack; var vs:integer;var vs2:integer);

var

y,u,o,o1,q,r,x,z:string;

w,c,c1,c2:integer;

q1,r1:real;

Begin

Udal(s,vs,c,x,z);

Udal(st,vs2,c,u,z); Chislo(u);

Udal(st,vs2,c,y,z); Chislo(y);

if x='+' then begin write(y,'+',u,'='); Summa(y,u,o); Cel_chast(o,o1);writeln(o1) end else

if x='-' then begin write(y,'-',u,'=');Raznost(y,u,o); Cel_chast(o,o1);writeln(o1) end else

if x='/' then begin write(y,':',u,'=');Delenie(y,u,o); Cel_chast(o,o1);writeln(o1) end else

if x='*' then begin write(y,'*',u,'=');Umn(y,u,o); Cel_chast(o,o1);writeln(o1) end;

Dobav(st,vs2,c,o,z);

End;

BEGIN

writeln('Введите пример, в котором можно использовать скобки и 4 арифметических знака: +, -, *, /.');

readln(p);

if copy(p,1,1)='-' then p:='0'+p;

d:=pos('(-',p);

while d<>0 do begin

Insert('0',p,d+1);

d:=pos('(-',p);

end;

d:=length(p);

i:=1;

v:='';

t:='';

f:=true;

e:='';

while i<=d do begin

x:=p[i];

if x='(' then w:=1 else

if x=')' then w:=2 else

if (x='+') or (x='-') then w:=3 else

if (x='*') or (x='/') then w:=4 else

if x=' ' then w:=6 else w:=5;

case w of

1:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:='';end;

e:='0';f:=false;

Dobav(s,vs,c,x,e);

end;

2:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:='';end;

while s[1,vs]<>'(' do Deystvie(s,st,vs,vs2);

Udal(s,vs,c,y,z);

e:='0'; f:=false;

end;

3:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:=''; end;

e:='1'; f:=false;

while (s[2,vs]>=e) and (s[2,vs]<>'0') do Deystvie(s,st,vs,vs2);

Dobav(s,vs,c,x,e);

end;

4:begin

if f and (t<>'') then begin Dobav(st,vs2,c,t,e);t:='';end;

e:='2'; f:=false;

while (s[2,vs]>=e) and (s[2,vs]<>'0') do Deystvie(s,st,vs,vs2);

Dobav(s,vs,c,x,e);

end;

5:begin t:=t+x;f:=true;end;

6:begin while p[i]<>'/' do

begin

t:=t+p[i];

i:=i+1;

end;

t:=t+p[i];

f:=true;

end;

else writeln('Mistake');

end;

i:=i+1;

end;

if t<>'' then Dobav(st,vs2,c,t,e);

while vs<>0 do

Deystvie(s,st,vs,vs2);

z:=st[1,vs2];

Cel_chast(z,x);

writeln(x);

readln;

End.

Использование структур стек и очередь при решении задач

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

Задача 1. «Грядки». Садовый участок разбит на квадратные клетки со стороной 1 метр и имеет размер М*N метров. На участке вскопаны грядки, представляющие собой прямоугольные конфигурации, не соприкасающиеся ни по вертикали, ни по горизонтали. Определить общее количество грядок и количество квадратных грядок. Грядки, совпадающие по диагонали, считаются разными грядками.

Структура очередь.

Program Gryadki;

{uses crt; }

const max = 100;

type

p = array[1..2,1..max] of shortint;

var

m,n,i,j,x,y:integer;

w,c,d,l,k,s:integer;

f,kvadr,kol:byte;

a:array[1..10,1..10] of shortint;

q:p;

Procedure Pusto(var q:p;var c,d:integer);

begin

c:=1; d:=1;

end;

Function Prover(var q:p;var c,d:integer):boolean;

begin

if c=d then Prover:=true else Prover:=false;

End;

Procedure Dobav(var q:p;var c,d:integer; var s:integer;

var a,b:integer);

begin

if d>max then begin s:=0; exit; end;

q[1,d]:=a; q[2,d]:=b;

d:=d+1;

s:=1; {добавили успешно}

End;

Procedure Udalen(var q:p;var c,d:integer; var s:integer);

begin

if Prover(q,c,d) then begin s:=0; exit; end;

c:=c+1;

s:=2; {удаление прошло успешно}

End;

BEGIN {clrscr;}

kol:=0;

write('m='); readln(m);

write('n='); readln(n);

writeln('если в этой позиции грядки нет - (-1), иначе - 0');

for i:=1 to m do

for j:=1 to n do begin

write('a[',i,';',j,']=');

readln(a[i,j]); end;

Pusto(q,c,d);

k:=0; {номер грядки}

for i:=1 to m do

for j:=1 to n do

if a[i,j]=0 then begin

kvadr:=0;

k:=k+1;

Dobav(q,c,d,s,i,j);

a[i,j]:=k;

kvadr:=kvadr+1;

while c<>d do

for l:=c to d do begin

x:=q[1,l]; y:=q[2,l];

if (x>1) and (a[x-1,y]=0) then begin w:=x-1;

Dobav(q,c,d,s,w,y);

a[w,y]:=k;

kvadr:=kvadr+1;

end;

if (x<m) and (a[x+1,y]=0) then begin w:=x+1;

Dobav(q,c,d,s,w,y);

a[x+1,y]:=k;

kvadr:=kvadr+1;

end;

if (y>1) and (a[x,y-1]=0) then begin w:=y-1;

Dobav(q,c,d,s,x,w);

a[x,y-1]:=k;

kvadr:=kvadr+1;

end;

if (y<n) and (a[x,y+1]=0) then begin w:=y+1;

Dobav(q,c,d,s,x,w);

a[x,y+1]:=k;

kvadr:=kvadr+1;

end;

Udalen(q,c,d,s);

end;

if sqrt(kvadr)=round(sqrt(kvadr))

then begin f:=1;

for w:=i to i+round(sqrt(kvadr))-1 do

for l:=j to j+round(sqrt(kvadr))-1 do

if a[i,j]<>a[w,l] then f:=2;

if f=1 then kol:=kol+1;

end; end;

writeln('Количество грядок k=',k);

writeln('Количество квадратных грядок ',kol);

readln;

END.

Задача 2. «Шахматы». Имеется шахматная доска. Некоторые поля на ней заняты белыми и черными фигурами и пешками. Каждое занятое поле белыми фигурами и пешками определяется числом -1, черными фигурами определяется числом 1. Необходимо определить маршрут белого коня с поля (Хн,Ун) на поле (Хк,Ук), при котором количество ходов минимально. Сбивание черной фигуры или пешки считается как два хода.

Структура очередь.

program Kon;

{uses crt;}

const max=100;

type p=array[1..3,1..max] of shortint;

var

m,n,i,j,x,y,z,nx,ny,kx,ky:integer;

w1,w,c,d,k,s,h,l:integer;

a:array[1..10,1..10] of shortint;

q,v:p;

Procedure Pusto(var q:p;var c,d:integer);

begin

c:=1; d:=1;

end;

Function Prover(var q:p;var c,d:integer):boolean;

begin

if c=d then Prover:=true else Prover:=false;

end;

Procedure Dobav(var q:p;var c,d:integer; var s:integer; var a,b,e:integer);

begin

if d>max then begin s:=0; exit; end;

q[1,d]:=a; q[2,d]:=b;

q[3,d]:=e;

d:=d+1;

s:=1;

End;

Procedure Udalen(var q:p;var c,d:integer; var s:integer);

begin

if Prover(q,c,d) then begin s:=0; exit; end;

c:=c+1; s:=2;

End;

BEGIN

{clrscr;}

write('m='); readln(m);

write('n='); readln(n);

writeln('Введите значения клеток:0-свободная,1-с чёрной фигурой,-1-с белой фигурой');

for i:=1 to m do

for j:=1 to n do begin

write('a[',i,',',j,']=');

readln(a[i,j]); end;

write('nx=');readln(nx);

write('ny=');readln(ny);

if a[nx,ny]<>0 then begin writeln('Конь не будет начинать свой путь в занятой клетке!'); readln; exit; end;

write('kx=');readln(kx);

write('ky=');readln(ky);

if a[kx,ky]=-1 then begin writeln('Конь не будет заканчивать свой путь в занятой белой фигурой клетке!'); readln; exit; end;

Pusto(q,c,d);

l:=0;

Dobav(q,c,d,s,nx,ny,l);

a[nx,ny]:=-1;

z:=0;

while c<>d do begin

x:=q[1,c];

y:=q[2,c];

l:=m*n;

for i:=1 to d-1 do

if (q[1,i]=x) and (q[2,i]=y) then

if l>q[3,i] then l:=q[3,i];

a[x,y]:=-1;

q[3,c]:=l;

h:=q[3,c];

if (x>1) and (y>2) and (a[x-1,y-2]<>-1)

then begin

w:=x-1;

w1:=y-2;

if a[x-1,y-2]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x>2) and (y>1) and (a[x-2,y-1]<>-1)

then begin

w:=x-2;

w1:=y-1;

if a[x-2,y-1]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x<m) and (y<n-1) and (a[x+1,y+2]<>-1)

then begin

w:=x+1;

w1:=y+2;

if a[x+1,y+2]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x<m-1) and (y<n) and (a[x+2,y+1]<>-1)

then begin

w:=x+2;

w1:=y+1;

if a[x+2,y+1]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x>1) and (y<n-1) and (a[x-1,y+2]<>-1)

then begin

w:=x-1;

w1:=y+2;

if a[x-1,y+2]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x>2) and (y<n) and (a[x-2,y+1]<>-1)

then begin

w:=x-2;

w1:=y+1;

if a[x-2,y+1]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x<m-1) and (y>1) and (a[x+2,y-1]<>-1)

then begin

w:=x+2;

w1:=y-1;

if a[x+2,y-1]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

if (x<m) and (y>2) and (a[x+1,y-2]<>-1)

then begin

w:=x+1;

w1:=y-2;

if a[x+1,y-2]=1 then k:=h+2 else k:=h+1;

Dobav(q,c,d,s,w,w1,k);

end;

Udalen(q,c,d,s);

l:=m*n;

for i:=1 to d-1 do

if (q[1,i]=kx) and (q[2,i]=ky) then begin

z:=1;

if l>q[3,i] then l:=q[3,i];

end;

end;

if z<>0 then writeln(l,' шаг(-ов,-а)') else writeln('Такого пути нет!');

{ for i:=1 to 3 do begin

for j:=1 to d-1 do

write(q[i,j]:3);

writeln; end;}

readln;

END.

Задача 3. Баланс скобок.

1. В строке расположена последовательность символов. Среди символов имеются символы скобки [({,})], расставленные с соблюдением баланса. Необходимо записать в новой строке все символы, расположенные вне скобок, а затем в обратном порядке символы, заключенные в скобки.

Пример: Исходная информация - ABC{D(E)F}KLM{Z[H]O}BN

Результирующая строка - ABCKLMBNOHZFED

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

Примечание: Скобки могут быть вложенными. ASD{G{H[(J)K]}VB}XCV. Для отслеживания скобок использовать стек.

program Skobki;

const

max=20;

type

stack=array[1..max] of char;

var

x:char;

v,t,p:string;

s:stack;

k,d,i,c,vs:integer;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0;

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false;

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer;

var x:char);

Begin

if vs=max then begin c:=0; exit; end;

vs:=vs+1;

s[vs]:=x;

c:=1;

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer;

var x:char);

Begin

if Prover(vs) then begin c:=0; exit; end;

x:=s[vs];

vs:=vs-1;

c:=0;

End;

BEGIN

Pusto(s,vs);

writeln('Введите выражение со скобками');

readln(p);

d:=length(p);

i:=1;

k:=0;

while i<=d do begin

x:=p[i];

case x of

'(','[','{':begin Dobav(s,vs,c,x); k:=k+1 end;

')':begin Dobav(s,vs,c,x); k:=k-1 end;

']':begin Dobav(s,vs,c,x); k:=k-1 end;

'}':begin Dobav(s,vs,c,x); k:=k-1 end;

'A'..'Z':if k=0 then v:=v+x else Dobav(s,vs,c,x);

end;

i:=i+1;

end;

while vs<>0 do begin

case s[vs] of

'A'..'Z':v:=v+s[vs];

end;

vs:=vs-1;

end;

writeln('Полученное выражение ',v);

readln;

End.

Задача 4.Корректировка текста

В строке-предложении со стандартным набором разделителей между словами (' ',:; -) встречается корректирующий символ *. Предложение заканчивается точкой. Если он встречается четное количество раз, то из строки удаляется аналогичное количество предшествующих ему символов; если он встречается нечетное количество раз, то из строки удаляется предшествующее им аналогичное количество слов. Скорректировать строку и вывести ее в обратном порядке.

program predl;

const

max=100;

type

stack=array[1..max] of char;

var

x,x1:char;

v,p:string;

g,s:stack;

k,d,i,j,c,vs:integer;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer;

var x:char);

Begin

if vs=max then begin c:=0; exit end;

vs:=vs+1;

s[vs]:=x;

c:=1

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer;

var x:char);

Begin

if Prover(vs) then begin c:=0; exit end;

x:=s[vs];

vs:=vs-1;

c:=0

End;

BEGIN

Pusto(s,vs);

writeln('Введите предложение, где могут встречаться знаки * один или несколько раз:');

readln(p);

d:=length(p);

i:=1;

k:=0;

while i<=d do

begin

x:=p[i];

case x of

'*': k:=k+1;

else

if k mod 2=0 then begin

for j:=1 to k do

Udal(s,vs,c,x1);

Dobav(s,vs,c,x);

k:=0

end

else begin

for j:=1 to k do begin

Udal(s,vs,c,x1);

while (x1<>' ') and (x1<>'-') and

(x1<>',') and (x1<>';') and

(x1<>':') do

Udal(s,vs,c,x1);

Dobav(s,vs,c,x1);

Dobav(s,vs,c,x) end;

k:=0

end

end;

i:=i+1

end;

for i:=vs downto 1 do

v:=v+s[i];

writeln(v);

readln

END.

Задача 5. Чередование

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

program glasn_soglasn;

const

max=20;

type

stack=array[1..max] of char;

var

x:char;

v,p:string;

g,s:stack;

d,i,c,vs,vg:integer;

Procedure Pusto(var s:stack;var vs:integer);

begin

vs:=0

End;

Function Prover(vs:integer):boolean;

Begin

if vs=0 then Prover:=true else Prover:=false

End;

Procedure Dobav(var s:stack;var vs:integer; var c:integer;

var x:char);

Begin

if vs=max then begin c:=0; exit end;

vs:=vs+1;

s[vs]:=x;

c:=1

End;

Procedure Udal(var s:stack;var vs:integer; var c:integer;

var x:char);

Begin

if Prover(vs) then begin c:=0; exit end;

x:=s[vs];

vs:=vs-1;

c:=0

End;

BEGIN

Pusto(s,vs);

Pusto(g,vg);

writeln('Введите строку, состоящую из больших латинских букв');

readln(p);

d:=length(p);

i:=1;

while i<=d do

begin

x:=p[i];

case x of

'A','E','I','O','U','Y': Dobav(g,vg,c,x)

else Dobav(s,vs,c,x)

end;

i:=i+1

end;

v:='';

if vs>vg then i:=vg else i:=vs;

for d:=1 to i do

v:=v+g[d]+s[d];

if i=vg then

for d:=vg+1 to vs do

v:=v+s[d]

else

for d:=vs+1 to vg do

v:=v+g[d];

writeln(v);

readln

END.

Задача 6. Ищу путь

Имеется лабиринт, представленный матрицей размером N*M, где 0 означает проходимая клетка, а 1 - непроходимая клетка. Найти выход из лабиринта, используя стратегию «держусь за стенку» (конечной клеткой может быть любая крайняя клетка матрицы). В решении использовать стек.

program labirint;

const

max=100;

type

stack=array[1..2,1..max] of integer;

var

a:array[1..20,1..20] of byte;

s:stack;

k,xn,yn,n,m,i,j,c,vs:integer;

Procedure Pusto(var s:stack;var vs:integer);


Подобные документы

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

    контрольная работа [345,6 K], добавлен 26.11.2020

  • Динамічні структури даних. Списки та їх різновиди. Практична реалізація динамічних структур на мові програмування С++. Динамічна пам’ять, операції NEW та DELETE. Побудова динамічних структур з використанням стандартних шаблонів: бібліотеки Stack та Queue.

    курсовая работа [72,4 K], добавлен 07.09.2010

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

    презентация [895,9 K], добавлен 14.10.2013

  • Основные понятия объектно-ориентированного программирования, особенности описания функций и классов. Разработка программы для работы с универсальной очередью установленного типа, добавления и удаления ее элементов и вывода содержимого очереди на экран.

    курсовая работа [187,2 K], добавлен 27.08.2012

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

    контрольная работа [290,6 K], добавлен 17.07.2012

  • Понятие стека как структуры данных, где элемент, занесенный первым, извлекается последним. Порядок добавления и удаления элементов списка. Реализация функций стека. Использование стека в алгоритме быстрой сортировки. Основные требования к элементам стека.

    презентация [591,2 K], добавлен 22.10.2013

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

    курсовая работа [459,0 K], добавлен 09.08.2012

  • Вычисление суммы положительных элементов массива. Упорядочивание элементов массива по убыванию. Решение задачи с помощью алгоритма, реализованного в среде Microsoft Visual 2008 Express. Реализация и тестирование программы. Выполнение трассировки функций.

    практическая работа [146,3 K], добавлен 23.01.2015

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

    курсовая работа [254,3 K], добавлен 20.05.2013

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

    курсовая работа [299,9 K], добавлен 07.06.2014

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.