堆栈解析算术表达式

利用栈,解析算术表达式问题就立刻变得容易许多。给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式。

中缀表达式和后缀表达式
中缀表达式就是通常所说的算术表达式,比如(1+2)*3-4。
后缀表达式是指通过解析后,运算符在运算数之后的表达式,比如上式解析成后缀表达式就是12+3*4-。这种表达式可以直接利用栈来求解。

运算符的优先级

优先级

运算符

1

括号()

2

负号-

3

乘方**

4

乘*,除/,求余%

5

加+,减-

6

小于<,小于等于<=,大于>,大于等于>=

7

等于==,不等于!=

8

逻辑与&&

9

逻辑或||


大致的规律是,一元运算符 > 二元运算符 > 多元运算符。

利用堆栈解析算术表达式的过程
中缀表达式翻译成后缀表达式的方法如下:
(1)从左向右依次取得数据ch。
(2)如果ch是操作数,直接输出。
(3)如果ch是运算符(含左右括号),则:
a:如果ch = '(',放入堆栈。
b:如果ch = ')',依次输出堆栈中的运算符,直到遇到'('为止。
c:如果ch不是')'或者'(',那么就和堆栈顶点位置的运算符top做优先级比较。
1:如果ch优先级比top高,那么将ch放入堆栈。
2:如果ch优先级低于或者等于top,那么输出top,然后将ch放入堆栈。
(4)如果表达式已经读取完成,而堆栈中还有运算符时,依次由顶端输出。
如果我们有表达式(A-B)*C+D-E/F,要翻译成后缀表达式,并且把后缀表达式存储在一个名叫output的字符串中,可以用下面的步骤。
(1)读取'(',压入堆栈,output为空
(2)读取A,是运算数,直接输出到output字符串,output = A
(3)读取'-',此时栈里面只有一个'(',因此将'-'压入栈,output = A
(4)读取B,是运算数,直接输出到output字符串,output = AB
(5)读取')',这时候依次输出栈里面的运算符'-',然后就是'(',直接弹出,output = AB-
(6)读取'*',是运算符,由于此时栈为空,因此直接压入栈,output = AB-
(7)读取C,是运算数,直接输出到output字符串,output = AB-C
(8)读取'+',是运算符,它的优先级比'*'低,那么弹出'*',压入'+",output = AB-C*
(9)读取D,是运算数,直接输出到output字符串,output = AB-C*D
(10)读取'-',是运算符,和'+'的优先级一样,因此弹出'+',然后压入'-',output = AB-C*D+
(11)读取E,是运算数,直接输出到output字符串,output = AB-C*D+E
(12)读取'/',是运算符,比'-'的优先级高,因此压入栈,output = AB-C*D+E
(13)读取F,是运算数,直接输出到output字符串,output = AB-C*D+EF
(14)原始字符串已经读取完毕,将栈里面剩余的运算符依次弹出,output = AB-C*D+EF/-

计算算术表达式(当然也可以边解析边运算,这样更快)
当有了后缀表达式以后,运算表达式的值就非常容易了。可以按照下面的流程来计算。
(1)从左向右扫描表达式,一个取出一个数据data
(2)如果data是操作数,就压入堆栈
(3)如果data是操作符,就从堆栈中弹出此操作符需要用到的数据的个数,进行运算,然后把结果压入堆栈
(4)如果数据处理完毕,堆栈中最后剩余的数据就是最终结果。
比如我们要处理一个后缀表达式1234+*+65/-,那么具体的步骤如下。
(1)首先1,2,3,4都是操作数,将它们都压入堆栈
(2)取得'+',为运算符,弹出数据3,4,得到结果7,然后将7压入堆栈
(3)取得'*',为运算符,弹出数据7,2,得到数据14,然后将14压入堆栈
(4)取得'+',为运算符,弹出数据14,1,得到结果15,然后将15压入堆栈
(5)6,5都是数据,都压入堆栈
(6)取得'/',为运算符,弹出数据6,5,得到结果1.2,然后将1.2压入堆栈
(7)取得'-',为运算符,弹出数据15,1.2,得到数据13.8,这就是最后的运算结果

例题  HDU1237 

我的代码:

#include<stdio.h>
#include<string.h>
#include<stack>
#include<iostream>
using namespace std;
int i;
double a,b;
char s[250],c;
int main()
{
    while(gets(s),strcmp(s,"#")!=0)
    {
        stack<char>s1;
        stack<double>s2;
        for(i=0;s[i];i++)
        {
            if(s[i]>='0'&&s[i]<='9') //如果是数字继续找数字
            {
                a=0;
                while(s[i]>='0'&&s[i]<='9')
                {
                    a=a*10+s[i]-'0';
                    i++;
                }
                i--;
                s2.push(a);
            }
            else if(s[i]=='(') //如果(
            {
                s1.push(s[i]);
            }
            else if(s[i]==')') //如果)
            {
                while(s1.top()!='(')//找不到前括号就循环
                {
                    c=s1.top();//符号top
                    s1.pop();//删掉
                    a=s2.top();//数字top
                    s2.pop();//删掉
                    b=s2.top();//当前数字top
                    s2.pop();//删掉
                    if(c=='+') a+=b;
                    if(c=='-') a=b-a;
                    if(c=='*') a=b*a;
                    if(c=='/') a=b/a;
                    s2.push(a);
                }
                s1.pop();//删除前括号
                if(s1.empty()==1){continue;}
                if(s1.top()=='*') //去掉括号以后栈还是乘
                {
                    s1.pop();//删掉
                    a=s2.top();//数字top
                    s2.pop();//删掉
                    b=s2.top();//当前数字top
                    s2.pop();//删掉
                    a=b*a;
                    s2.push(a);
                }
            }
            else if(s[i]=='-'||s[i]=='+') //如果是+-
            {
                if(s1.empty()==0&&s1.top()!='(')//优先级低或者一样交换符号
                {
                    c=s1.top();//字符栈顶
                    s1.pop();//删掉
                    a=s2.top();//数字栈顶1
                    s2.pop();//删掉
                    b=s2.top();//数字栈顶2
                    s2.pop();//删掉
                    if(c=='+') a+=b; 
                    if(c=='-') a=b-a;
                    if(c=='*') a=b*a;
                    if(c=='/') a=b/a;
                    s2.push(a);//运算以后的入数字栈
                    s1.push(s[i]);//字符入栈
                }
                else if(s1.empty()==1||s1.top()=='(')//如果空或者前括号
                {
                    s1.push(s[i]);//字符入栈
                }
            }
            else if(s[i]=='/') //如果除
            {
                b=0;
                c=s[i];//存一下符号
                if(s1.empty()==1||s1.top()=='(') //空就入栈不运算
                {
                    s1.push(c);
                    continue;
                }
                i+=2;//找符号后面的数字
                while(s[i]>='0'&&s[i]<='9')
                {
                    b=b*10+s[i]-'0';
                    i++;
                }
                i--;//找到数字
                a=s2.top();//取出数字栈顶
                s2.pop();//删掉
                if(s1.top()=='*') //优先级一样交换符号
                {
                    a=a*b;
                    s1.pop();//删除原来的
                    s1.push(c);//换成新的
                }
                else a=a/b;//优先级高做除法
                s2.push(a);//新数字入栈
            }
            else if(s[i]=='*') //如果乘
            {
                b=0;
                c=s[i];
                if(s1.empty()==1||s1.top()=='(')
                {
                    s1.push(c);
                    continue;
                }
                i+=2;
                if(s[i]=='(')
                {
                    s1.push(c);
                    i--;
                    continue;
                }
                while(s[i]>='0'&&s[i]<='9')
                {
                    b=b*10+s[i]-'0';
                    i++;
                }
                i--;
                a=s2.top();
                s2.pop();
                if(s1.top()=='/')
                {
                    a=a/b;
                    s1.pop();
                    s1.push(c);
                }
                else if(s1.top()!='/')
                {
                    a=a*b;
                }
                s2.push(a);
            }
            
        }
        while(!s1.empty())//如果符号栈非空就循环
        {
            c=s1.top();//符号top
            s1.pop();//删掉
            a=s2.top();//数字top
            s2.pop();//删掉
            b=s2.top();//当前数字top
            s2.pop();//删掉
            if(c=='+') a+=b;
            if(c=='-') a=b-a;
            if(c=='*') a=b*a;
            if(c=='/') a=b/a;
            s2.push(a);
        }
        printf("%.2f
",s2.top());
    }
    return 0;
 }
添加了括号功能
原文地址:https://www.cnblogs.com/dzzy/p/4779612.html