算术表达式求值

实验3 算术表达式求值

一、实验目的

  熟练掌握栈的结构,以及这种数据结构的特点;

2  能够在两种存储结构上实现栈的基本运算,特别注意栈满和栈空的判断条件及描述方法;

二、实验原理

要求输入表达式,判断括号是否匹配,若匹配则由中缀表达式转化为后缀表达式,并通过运算得出计算结果。

1. Match()验证括号是否匹配当遇到左括号时就入栈,遇到右括号时就取栈顶元素,如果栈顶元素是左括号,那么匹配成功,同时将左括号出栈。不匹配情况:(1)左括号多,循环结束时,栈中还存在元素即左括号。(2)右括号多,取栈顶元素时,栈顶为空则没有左括号了。

2. 中缀转后缀两个存储空间,str2存放数字或运算符,栈s存放运算符

       12+3*4:“*”号优先级大于“+”号,可直接入栈

首先2为数字插入str2尾部,“+”此时栈为空所以加号入栈,3为数字插入str2尾部,“*”号优先级大于“+”号,所以可以直接入栈,4为数字插入str2尾部,循环结束。但是此时栈不为空:把栈中所有元素出栈并插入str2尾部。得到:str2=234*+

(2)2+3*4:遇到右括号则栈中所有元素出栈,插入str2尾部

首先是“(”则可直接入栈,2为数字插入str2尾部,“+”号优先级大于“(”直接入栈,3为数字插入str2尾部,“)”则把栈中所有元素出栈,插入到str2尾部(左括号不插入),“*”此时栈为空可直接入栈,4为数字插入str2尾部,循环结束。但是此时栈中还有一个“*”号,把栈中所有元素出栈并插入str2尾部。得到:str2=23+4*

32+3*4-5:减号优先级小于乘号,把栈中所有元素出栈,插入str2尾部

首先2为数字插入str2尾部,“+”此时栈为空可直接入栈,3为数字插入str2尾部,“*”号优先级大于“+”号可直接入栈,4位数字插入str2尾部,“-”号优先级低于“*”号,把栈中所有元素出栈,插入str2尾部,此时栈为空减号直接入栈,5为数字插入str2尾部,循环结束。但是此时栈中还有一个“-”号,把栈中所有元素出栈并插入str2尾部。得到:str2=234*+5-

3.通过后缀表达式计算结果:遇到数字就入栈ss中,遇到运算符就取栈顶的两个元素,进行计算,计算结果还放入栈ss中。最终计算结果在栈ss中。

 

三、参考程序

#include<iostream>  

#include<cstdio>  

#include<cstring>  

#include<malloc.h>

#include<string>  

#include<stack>  

using namespace std;  

const int MaxSize=100;  

stack<char> s;    //定义一个栈s  

stack<int> ss;    //定义一个栈ss

 

typedef struct linknode  

{  

    char data[MaxSize];  

    int top;  

}SqStack;  

  //初始化栈

void initStack(SqStack *&s)     

{  

    s=(SqStack *)malloc(sizeof(SqStack));  

    s->top=-1;  

}  

  //入栈操作

bool Push(SqStack *&s,char e)     

{  

    if(s->top==MaxSize-1)  //栈已满

        return false;  

    s->top++;  //入栈

    s->data[s->top]=e;  

    return true;  

}  

  //出栈操作

bool Pop(SqStack *&s,char &e)     

{  

    if(s->top==-1)  

        return false;  

    e=s->data[s->top];  

    s->top--;  

    return true;  

}  

  //获得栈顶元素

bool GetTop(SqStack *s,char &e)      {  

    if(s->top==-1)  //栈已空

        return false;  

    e=s->data[s->top];  

    return true;  

}  

  //清空栈

bool StackEmpty(SqStack *s)        

{  

    return(s->top==-1);  

}  

  //销毁栈

void DestroyStack(SqStack *&s)       

{  

    free(s);  

}  

  //括号是否匹配

bool Match(char exp[],int n)   

{  

    int i=0;  

    char e;  

    bool match=true;  

    SqStack *sq;  

    initStack(sq);  

    while(i<n && match)  

    {  

        if(exp[i]=='(')      //如果当前元素为(

            Push(sq,exp[i]);      //将当前元素入栈

        else if(exp[i]==')')     //如果当前元素为)

        {  

            if(GetTop(sq,e)==true)     //存在栈顶元素

            {  

                if(e!='(')        //如果该元素不是左括号

                    match=false;       //则不匹配

                else  

                    Pop(sq,e);      //是左括号就出栈

                    match = true;

            }  

            else match=false;     //若栈为空,则不匹配

         }

        if(exp[i]=='[')      //如果当前元素为【

            Push(sq,exp[i]);      //将当前元素入栈

        else if(exp[i]==']')     //如果当前元素为】

        {  

            if(GetTop(sq,e)==true)     //取栈顶元素

            {  

                if(e!='[')        //如果该元素不是【

                    match=false;       //则不匹配

                else  

                    Pop(sq,e);      //否则,将该元素出栈

            }  

        

            else match=false;     //若栈为空,则不匹配

        }

        if(exp[i]=='{')      //如果当前元素为 {

            Push(sq,exp[i]);      //将当前元素入栈

        else if(exp[i]=='}')     //如果当前元素为 }

        {  

            if(GetTop(sq,e)==true)     //取栈顶元素

            {  

                if(e!='{')        //如果该元素不是 {

                    match=false;       //则不匹配

                else  

                    Pop(sq,e);      //否则,将该元素出栈

            }  

            else match=false;     //若栈为空,则不匹配

        }

        ++i;    //判断下一个元素

}

    if(!StackEmpty(sq))  match=false;     //执行完上述程序后,如果栈不为空 ,则匹配不成功,因为只要匹配就把左括号出栈了,如果还有表示多左括号

    DestroyStack(sq);     //销毁栈

    return match;     //返回match值

}

int main()

{

char st[100];  

int len1, len2, len, i, j;  

      string str1, str2;//str1为中缀表达式,str2为后缀表达式

         

    //检测Match()函数值

    cout<<"请输入表达式:"<<endl;

    cin>>st;    //输入字符

    int len0=strlen(st);//所输入字符串的实际长度

bool m=Match(st,len0);//通过match()函数判断输入的式子中括号是否匹配

//中缀表达式转换为后缀表达式   

    if (m==true)

{      //如果match=true

     cout<<"ok!"<<endl;     //输出匹配成功

     cout<<"请再次输入刚刚输入过的表达式:"<<endl;

     cin>>str1;

     len1 = str1.length();    //中缀表达式的长度

     str2.clear();      //清除流的错误状态

//原则:数字存入字符串str2尾部,运算符进栈或出栈

     for (i = 0; i < len1; i++){  

         if (str1[i] >= '0' && str1[i] <= '9')   

                 str2.push_back(str1[i]);     //如果是中缀表达式中的数字,则在后缀表达式字符串尾部插入这个数字

         else{   

             if (s.size() == 0 || str1[i] == '(')  //如果栈s中元素数目为0,或者该元素是中缀表达式中的(

                 s.push(str1[i]);    //让该元素进栈

             else{  

                 char tmp1 = s.top();    //将栈顶元素赋给tmp1

                 if (str1[i] == ')')//如果该元素是右括号,就把栈中所有元素出栈,并插入str2尾部

{      

                    len = s.size();   //将s栈中元素数目赋给len

                    while (len)

{     //len不为空

                            char tmp = s.top();//将栈s的栈顶元素赋给tmp变量

                            s.pop();    //出栈

                           if (tmp == '(')     //如果tmp等于左括号, 不加入str2中

                             break;     //跳出while循环

                           else   

                                  str2.push_back(tmp);    //否则将tmp插入到后缀表达式字符串尾部

                         len--;    //长度-1

                     }   

                 }   

                 else{  

                         if (tmp1 == '*' || tmp1 == '/'){      //如果栈顶元素tmp1为*号或/号  

                           if (str1[i] == '*' || str1[i] == '/')    //当前元素也为*号或/号,优先级相同直接入栈

                                s.push(str1[i]);    //将该元素入栈

                            else{  //如果中缀字符串里的该元素不是*号或/号,优先级低,那么所有元素出栈,插到str2尾部

                                len = s.size();    

                                 while (len){  

                                     char tmp = s.top();   

                                     str2.push_back(tmp);  

                                     s.pop();   

                                     len--;   

                                 }  

                                 s.push(str1[i]);    

                             }   

                         }   

                         else{     //如果栈顶元素tmp1不为*号或/号  

                             s.push(str1[i]);    //将该元素入栈

                         }   

                 }   

             }    

         }   

     }  

     if (s.size() != 0){  //循环结束后如果栈中还有元素,则全部出栈,插到str2尾部

         len = s.size();   

         while (len){  

             char tmp = s.top();     

             str2.push_back(tmp);    //并添加到后缀表达式后边

             s.pop();   //将所有元素出栈

             len--;   

         }   

     }   

     cout << "后缀表达式为:"<<endl<<str2 << endl;  

//由后缀表达式计算结果   

//str2是字符串,ss为栈

    int temp1, temp2, temp3;   

    len2 = str2.length();     //后缀表达式长度

    for (i = 0; i < len2; i++){  

        if (str2[i] >= '0' && str2[i] <= '9'){ //当前字符串是数字就入栈  

            int t = str2[i]-48;   

            ss.push(t);   

        }   

        else{  //如果新存入的不是数字,而是运算符,就把栈中最上面的两个元素出栈,通过计算再入栈

            temp1 = ss.top();  

            ss.pop();  

            temp2 = ss.top();  

            ss.pop();   

            if (str2[i] == '+'){  

                temp3 = temp2 + temp1;   

            }  

            else if (str2[i] == '-'){  

                temp3 = temp2 - temp1;   

            }  

            else if (str2[i] == '*'){  

                temp3 = temp2 * temp1;   

            }  

            else if (str2[i] == '/'){  

                temp3 = temp2 / temp1;   

            }  

            ss.push(temp3);//得到计算结果后,还入栈   

        }  

    }  

    cout <<"计算结果为:"<<endl<< ss.top() << endl;   

}

else  {

cout<<"error!"<<endl;      //否则,输出匹配为假

}  

    return 0;

}

/*运算结果:

请输入表达式:

4+(9-3)

ok!

请再次输入刚刚输入过的表达式:

4+(9-3)

后缀表达式为:

493-+

计算结果为:

10

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值