КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Пример вычисления арифметического выражения с помощью стеков
End. IMPLEMENTATION Procedure Push; Var t:u; Begin New(t); t^.i:= a; t^.L:= h; h:= t; End;
Function Pop; Var t:u; Begin Pop:= h^.i; t:= h; h:= h^.L; Dispose (t); End;
Function Empty; Begin Empty:= h = Nil; End;
Function Top; Begin Top:= h^.i; End; Одно из интереснейших применений стека - синтаксический разбор и вычисление выражения, например, арифметического. Пусть дана строка, являющаяся записью арифметического выражения. Возможно наличие бинарных операций '+', '-', '*', '/', левой и правой круглых скобок, в качестве операндов для простоты будем использовать цифры от 0 до 9. Выражение заканчивается знаком '='. Например, допустимым будет выражение 4-2/6*(2+3*6)=. Необходимо написать программу, вычисляющую значение этого выражения или выдающую сообщение об ошибке в нем. Попробуем сформулировать основные положения, которые нам понадобятся для вычисления выражения. 1.Операции выражения в скобках выполняются первыми, т.е. 2.Наивысший приоритет из четырех возможных арифметических операций имеют операции умножения и деления. При отсутствии скобок эти операции выполняются раньше, чем сложение и вычитание. 3.Операции с равными приоритетами выполняются в порядке их появления в выражении. Рассмотрим для начала выражение без скобок, например 8/2+3*4=. Сначала надо выполнить деление, далее - умножение, а затем - сложение. Причем складывать надо результаты первой и второй операций. Будем разбирать выражение по символу. Первый символ 8 - операнд, он нам понадобится позже, поэтому временно поместим его в стек операндов. Следующий символ - знак деления. Мы не знаем, что нам встретится позднее, возможно скобка, поэтому надо ли выполнять деление прямо сейчас, мы сказать не можем. Следовательно, поместим на время этот символ в стек операций. Следующий символ - тоже операнд, и мы поместим его в стек операндов. Далее идет знак сложения. Посмотрим, какие операции встречались до сложения, не надо ли их выполнить раньше. На вершине стека операций находится символ операции деления. Операция деления имеет больший приоритет, чем операция сложения, поэтому выполним теперь деление. Для этого вынем знак операции деления из стека операций, а также возьмем из стека операндов два верхних операнда: сначала - правый (2), затем -левый (8). Поделим левый операнд на правый. Получим значение 4. Оно понадобится нам и позже, поэтому временно положим его в стек операндов. Теперь текущим рассматриваемым символом является знак сложения. Если в стеке операций есть еще элементы, которые надо выполнить до сложения, то выполним их. Но у нас стек пуст. Какие операции встретятся дальше, мы не знаем, поэтому поместим пока знак сложения в стек операций и перейдем к следующему символу. Это операнд 3, поместим его в стек операндов. Перечислим снизу вверх элементы стека операндов: (4, 3). Далее следует знак умножения. Проверим, не было ли у нас операций, которые должны были быть до него выполнены (например, другое умножение). Верхним элементом в стеке операций у нас является знак сложения, так как умножение должно выполняться раньше, поместим его в стек над сложением. Таким образом, стек операций выглядит в следующим виде: ('+','*'). Следующий символ - операнд 4. Поместим его в стек операндов, в котором теперь будут храниться уже три элемента: (4, 3, 4). Следующий символ - знак равенства, означающий конец выражения. На вершине стека операций у нас знак умножения. Выполним эту операцию, вынув ее из стека и взяв два верхних операнда из стека операндов. Левый операнд у нас 3, а правый - 4. Результатом умножения будет 12. Поместим этот результат в стек операндов, теперь там два элемента: (4, 12). На вершине стека операций находится знак сложения. Выполним эту операцию. Левым операндом будет 4, правым - 12. Результатом будет 16, поместим 16 в стек операндов. Стек операций пуст, значит, в стеке операндов у нас находится результат. Удалим его из стека и выведем на экран. У нас получился верный результат вычисления выражения 8/2+3*4. Заметим, что для элементов стека операндов неудобно использовать тип Char, как для элементов стека операций. Целесообразно элементы стека операндов объявить как вещественные числа. Схема алгоритма: 1. 8 à Sd; (Sd – стек операндов (данных)) 2. / à So; (So – стек операций) 3. 2 à Sd; 4. +; смотрим Sо, там /, p(/) > p(+), поэтому выполним операцию /; 8: 2 = 4 à Sd. 5. Смотрим So. Если So ≠ Ǿ и p (операции) > p(+), то эти операции должны быть выполнены. Но у нас So= Ǿ, поэтому + à So. 6. 3 à Sd; 7. *: смотрим So → там +; так как p (+) < p(*), поэтому * à So; 8. 4 à Sd; 9. = конец выражения. 4 * 3 = 12 à Sd; 4 +12 = 16 à Sd; Sd à Ответ =16 Теперь посмотрим, какие необходимо выполнить действия, если в выражении есть скобки. В качестве примера разберем выражение 4*(2+3)=. Первый символ - операнд. Поместим его в стек операндов. Следующий символ - знак умножения. Операций, которые надо было выполнить до него, у нас нет, поэтому поместим этот символ в стек операций. Далее следует левая скобка. Это означает, что то, что будет записано далее, должно вычисляться раньше, чем то, что мы рассматривали до сих пор. Поместим левую скобку в стек операций, состояние стека: ('*','('). Далее у нас следует операнд. Поместим его в стек операндов, состояние стека операндов: (4, 2). Следующий символ - знак сложения. На вершине стека находится скобка, таким образом, у нас нет ничего, что надо было выполнить до сложения. Поместим сложение в стек операций, который теперь содержит три элемента: ('*','(','+'). Следующий символ - операнд. Поместим его в стек операндов, который теперь имеет следующее содержимое: (4, 2, 3). Далее у нас идет правая скобка, следовательно, выражение в скобках на этом заканчивается, надо его вычислить. Верхней операцией у нас является сложение, выполним его. В стеке операций у нас теперь два элемента: ('*', '('), в стеке операндов – тоже два: (4, 5). Выполним все операции, которые содержались в скобках, удалим из стека операций левую скобку (если ее в стеке нет, значит, в выражении была допущена ошибка). Перейдем теперь к следующему символу. Это знак '=', означающий конец выражения. Выполним верхнюю операцию в стеке – умножение. Теперь стек операций у нас пуст, а в стеке операндов хранится число 20. Это и есть результат вычисления нашего выражения. Итак, для каждого символа в выражении предусмотрены различные действия, причем действия с операциями зависят не только от самой операции, но и от того, что находится на вершине стека операций. Рассмотрим возможные варианты. Для символов '+' и '-' правила одинаковы: 1. Если стек пуст или верхний элемент - левая скобка, поместим 2. Если на вершине стека операция с равным приоритетом, выполнить ее, поместить рассматриваемую в данный момент операцию в стек и перейти к следующему символу. 3. Если на вершине стека операция с высшим приоритетом, выполнить эту операцию. Так как возможно, что до сложения или вычитания встретилась не одна операция, которая должна быть выполнена раньше рассматриваемой в данный момент, то к следующему символу пока не переходим. Правила для операций умножения и деления (для символов '*' и '/'). 1. Если стек пуст или на вершине находится левая скобка или операция с меньшим приоритетом, операция помещается в стек, и переходят к следующему символу. 2. Если на вершине стека находится операция с равным приоритетом, необходимо выполнить ее и поместить рассматриваемую в данный момент операцию в стек и перейти к следующему символу. В случае левой скобки необходимо добавить символ в стек операций и перейти к следующему символу. В случае правой скобки возможны следующие варианты: 1. Стек пуст. Следовательно, не хватает левой скобки, т.е. выражение ошибочно. 2. На вершине - левая скобка. Следовательно, выражение в скобках кончилось, удаляем левую скобку из стека и переходим к следующему символу. 3. На вершине стека - арифметическая операция. Вынимаем операцию из стека и выполняем ее. И наконец, рассмотрим действия, необходимые для обработки символа конца выражения. 1.Если стек пуст, то выражение вычислено. Следовательно, нужно удалить из стека операндов результат и вывести его. 2. На вершине - левая скобка. Следовательно, левых скобок в выражении было больше, чем правых, т.е. выражение ошибочно. 3. На вершине стека - арифметическая операция. Необходимо удалить ее из стека и выполнить. Итак, у нас шесть возможных вариантов действий. Для выбора того или иного действия необходимо проверить сочетание состояния вершины стека операций и рассматриваемый символ. Чтобы ускорить выбор нужной операции, составим матрицу, элементы которой будут соответствовать номеру действия, необхо
димого при данном состоянии стека и данной операции (табл.5.2.). Состояние стека определяется номером строки, операция - номером столбца. Обозначим состояние ошибки числом 0, а остальным вариантам присвоим номера от 1 до 5: 0 – ошибка; 1 – положить операцию в стек и перейти к следующему символу 2 – выполнить верхнюю операцию, положить рассматриваемую 3 – извлечь из стека операций верхний элемент и перейти к следующему символу выражения; 4 – выполнить верхнюю операцию; 5 – состояние конца выражения. Воспользуемся процедурами, описанными в модуле Stack для работы со стеком операций и напишем аналогичный модуль для работы со стеком данных. Далее составим программу вычисления арифметического выражения.
Program Compute; Uses CRT, So, Sd; { So –стек для знаков операций; Sd – стек для данных. } Const tab: Array [0..5,0..6] Of Byte =((5, 1, 1, 1, 1, 1, 0), (0, 1, 1, 1, 1, 1, 3), (4, 1, 2, 2, 1, 1, 4), (4, 1, 2, 2, 1, 1, 4), (4, 1, 4, 4, 2, 2, 4), (4, 1, 4, 4, 2, 2, 4));
Var ho:w; h:u; { указатели для стеков операций и данных} v:String; {в v исходное арифметическое выражение } Ok, f:Boolean; {флаги корректности и завершения} j, k:Integer; c:Char; res, x:Real; {рабочие переменные} ....................................................................................................................................... Function NumAct (sp:w; op:Char):Byte; { возвращает номер действия из таблицы tab; op – операция из вх. строки v } Var i:Byte;
Дата добавления: 2014-01-11; Просмотров: 1921; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |