Лабораторная работа №12. Алгоритм перевода выражения в обратную польскую запись (Алгоритм Дейкстра).
Задание 1.
Используя записи и указатели, а также функции динамического распределения памяти (NEW, DISPOSE), реализовать программу для алгоритма Дейкстра. (ошибки ввода учесть).
Алгоритм Дейкстра – алгоритм перевода выражения в обратную польскую запись. Обратная польская запись представляет собой промежуточную форму выражения, которая используется в компиляторах и интерпретаторах для вычисления значения выражения. В обратной польской записи отсутствуют скобки, а операции всегда следуют за операндами, а не между ними.
Алгоритм Дейкстра
1) В стек (стек – это структура данных, хранящая совокупность однотипных элементов, которые поступают в стек и выходят из него по правилу «последний вошел - первый вышел») будут помещаться только символы операций.
2) Символы операндов из входной строки поступают сразу в выходную строку.
3) Символы операций сначала поступают в стек и при определенных условиях выталкиваются в выходную строку.
4) Открывающаяся скобка всегда попадает в стек.
5) Закрывающаяся скобка ни в стек, ни в выходную строку не попадает.
6) Когда встречается в выходной строке закрывающаяся скобка, из стека выталкиваются все символы до первой встречной открывающейся скобки включительно. Причем знаки операций выталкиваются в выходную строку, а открывающаяся скобка пропадает.
7) Необходимо использовать приоритеты операций:
( 0
+, - 1
*, / 2
Чем больше значение приоритета, тем сильнее операция связывает операнды.
8) Если во входной строке текущий символ – знак операции, то сравниваются приоритеты операций из строки и верхушки стека.
9) Если приоритет операции из входной строки больше приоритета операции из верхушки стека, то операция из входной строки стека перемещается в стек. В противном случае из стека выталкиваются все операции с приоритетами большими либо равными приоритетам операций из входной строки. После чего операция из входной строки помещается в стек.
10) При встрече конца входной строки содержимое стека выталкивается в выходную строку.
Например:
Входная строка: (a+b*c)*(a-b)/(d-(a+b*d))
Стек:
( | + | * | * | ( | - | * | / | ( | - | ( | + | * | - | / |
( | + | * | ( | / | ( | - | ( | + | ( | |||||
( | * | / | ( | - | ( | / | ||||||||
/ | ( | - | ||||||||||||
/ | ( | |||||||||||||
/ |
Выходная строка: abc*+ab-*dabd*+-/
Рекомендации.
1) Стек можно рассматривать как случай списка.
Для стека обязательно наличие указателя на вершину.
2) Если стек пуст, то указатель на вершину пустой (NIL).
3) Для данного примера данные в структуре списка это символы и числа (приоритеты).
4) Для работы со стеком необходимы как минимум две процедуры: push(втолкнуть) и pop(вытолкнуть). Для процедуры push необходимы два параметра (символ и приоритет); для процедуры pop в общем случае параметры не нужны, но в нашем примере необходим один параметр типа Boolean (TRUE-выталкивать в выходную строку; FALSE-выталкивать, но не в выходную строку).
5) Желательно написать функцию, которая бы по входному параметру-символу выдавала его приоритет.
type
point=^elsteka;
elsteka=record
oper:char;
prior:integer;
next:point;
end;
var instr, outstr:string;
uk_steka:point;
procedure push (oper:char; prior:integer);
var r_uk:point;
begin new(r_uk);
r_uk^.next:=uk_steka;
uk_steka:=r_uk;
uk_steka^.oper:=oper;
uk_steka^.prior:=prior;
end;
procedure pop (priznak:boolean);
var r_uk:point;
begin
if (priznak) and (uk_steka^.oper<>'(') then
outstr:=outstr+uk_steka^.oper;
r_uk:=uk_steka^.next;
dispose (uk_steka);
uk_steka:=r_uk;
end;
function prior (oper:char):integer;
type
el_t_prior=record
oper:char;
prior:integer;
end;
const tabl_prior:array[0..4] of el_t_prior=
( (oper:'('; prior:0),
(oper: '-'; prior:1),
(oper:'+'; prior:1),
(oper: '*'; prior:2),
(oper:'/'; prior:2)
);
var i:integer;
begin
for i:=0 to 4 do begin
if tabl_prior[i].oper=oper then
begin
prior:=tabl_prior[i].prior;
exit;
end;
end;
end;
6) Графический алгоритм программы: