【ThinkingInC++】1、三写表达式求值

/**
* 功能:表达式求值
* 时间:2014年8月3日08:27:42
* 作者:cutter_point
*/

#include<iostream>
#include<cstdlib>
#include<sstream>
#include<string>

using namespace std;

/********************************************************************************/
string OP="+-*/()#";

//构建两个栈,一个数字栈一个字符栈
/********************************************************************************/
//数字栈的数据结构
typedef struct iStack
{
    int i;  //要用来计算的数字
    iStack* next;   //指向下一个节点
}*pIStack;

//字符栈的数据结构
typedef struct cStack
{
    char c; //操作符号
    cStack* next;   //指向下一个节点
}*pCStack;
/********************************************************************************/
//定义两个全局栈变量,并初始化为空
pIStack headIntSt=nullptr, tailIntSt=nullptr; //数字栈
pCStack headCharSt=nullptr, tailCharSt=nullptr; //字符栈

/********************************************************************************/
//栈的初始化,就是一个空的头节点initialise:初始化
void initialiseIStack()    //数字栈初始化
{
    //创建一个空的头结点
    pIStack p=new iStack;   //创建节点
    p->next=nullptr;
    headIntSt=p;  //设置为头结点(空的)
    tailIntSt=p;    //吧尾节点指向追后一个
}

void initialiseCStack()     //字符栈的初始化
{
    //创建一个空的头结点
    pCStack p=new cStack;   //创建节点
    p->next=nullptr;
    headCharSt=p;  //接入头结点
    tailCharSt=p;    //吧尾节点指向追后一个
}
/********************************************************************************/
//栈的弹出并吧栈的弹出元素删除一个
int popInt()       //给一个指针就是头指针,数字栈的删除
{
    pIStack p1;      //这两个指向最后一个的前一个,即倒数第二
    p1=headIntSt;
    //遍历找到倒数两个
    while(p1->next != tailIntSt)   //只要p1->next不指向尾节点
    {
        p1=p1->next;    //指向下一个节点
    }
    //取得尾节点的值准备返回

    int i=tailIntSt->i;

    //吧尾节点delete掉
    delete tailIntSt;
    //重置尾节点
    tailIntSt=p1;   //新的尾节点

    return i;
}

char popChar()       //给一个指针就是头指针,字符栈的删除
{
    pCStack p1;      //这两个指向最后一个的前一个,即倒数第二
    p1=headCharSt;
    //遍历找到倒数两个
    while(p1->next != tailCharSt)   //只要p1->next不指向尾节点
    {
        p1=p1->next;    //指向下一个节点
    }
    //取得尾节点的值准备返回

    char c=tailCharSt->c;

    //吧尾节点delete掉
    delete tailCharSt;
    //重置尾节点
    tailCharSt=p1;   //新的尾节点

    return c;
}

/********************************************************************************/
//栈的压入,增加一个节点
void pushInt(int e)      //数字栈的压入
{
    //创建一个节点
    pIStack p=new iStack;   //创建节点
    p->i=e;
    p->next=nullptr;

    //接入到尾节点后面
    tailIntSt->next=p;

    //重置尾节点
    tailIntSt=p;
}

void pushChar(char e)      //字符栈的压入
{
    //创建一个节点
    pCStack p=new cStack;   //创建节点
    p->c=e;
    p->next=nullptr;

    //接入到尾节点后面
    tailCharSt->next=p;

    //重置尾节点
    tailCharSt=p;
}

/********************************************************************************/
//返回优先级符号,对两个字符比较
/*
  +  -  *  /  (  )  #  这里代表c2
+ >  >  <  <  <  >  >
- >  >  <  <  <  <  <
* >  >  >  >  <  >  >
/ >  >  >  >  <  >  >
( <  <  <  <  <  =  ×
) >  >  >  >  >  >  >
# <  <  <  <  <  <  =
这个代表
c1
之间格式是
c1 符号 c2
*/
char isFirst(char c1, char c2)
{
    char res;   //返回优先级比较结果

    switch(c1)
    {
    case '+': case '-': //当第一个字符是这两个的时候
        switch(c2)  //和后面的字符比较
        {
        case '+': case '-': case ')': case '#':
            //当第二个字符是这些的时候,c1的优先级比他们大
            res='>';
            break;
        case '*': case '/': case '(':
            //当第二个字符是这些的时候,c1的优先级比他们小
            res='<';
            break;
        }
        break;
    case '*': case '/':
        switch(c2)  //和后面的字符比较
        {
        case '(':
            //当第二个字符是这些的时候,c1的优先级比他们小
            res='<';
            break;
        default:
            res='>';
            break;
        }
        break;
    case '(':
        switch(c2)  //和后面的字符比较
        {
        case ')':
            //当第二个字符是这些的时候,c1的优先级比他们大
            res='=';
            break;
        case '*': case '/': case '(': case '+': case '-': case '#':
            //当第二个字符是这些的时候,c1的优先级比他们小
            res='<';
            break;
        }
        break;
    case ')':
        res='>';
        break;
    case '#':
        switch(c2)
        {
        case '#':
            res='=';
            break;
        default:
            res='<';
            break;
        }
        break;
    }

    return res;
}
/********************************************************************************/
//是否是运算符验证
bool isOperator(char c)
{
    bool b=false;
//    string::size_type pos=0;


    for(auto it=OP.begin() ; it != OP.end() ; ++it) //一个个匹配
    {
        if(c == *it)    //只要出现匹配立马跳出循环
        {
            b=true;
            break;
        }
    }

    return b;
}
/********************************************************************************/
//操作符转换成真正的operator
int doOperator(int a, char o, int b)
{
    int res;

    switch(o)
    {
    case '+':
        res=a+b;
        break;
    case '-':
        res=a-b;
        break;
    case '*':
        res=a*b;
        break;
    case '/':
        res=a/b;
        break;
    }

    return res;
}

/********************************************************************************/
//表达式求值算法,求出表达式结果
/*
found=str.find_first_of("aeiou");
while (found!=string::npos)
{
    str[found]='*';
    found=str.find_first_of("aeiou",found+1);
}
*/
int result(string s)    //吧表达式字符串导入
{
    //首先清空栈,初始化
    initialiseIStack();
    initialiseCStack();
    pushChar('#');  //给栈底添加#元素

    while(s != "" || tailCharSt->c == '#')
    {
        //吧s分割成2快,第一个数字快和后面字符快
        int found=s.find_first_of(OP);
        string si=s.substr(0, found);   //第一个数字,不包括第found那个字符
        //吧数字入栈
        if(si != "")  //如果数字不为空,就是取到数字了而不是字符
        {
            int sitoi;  //si转化成的int类型

            stringstream stream(si);    //使用sstream头文件流来转化
            stream>>sitoi;      //转化为int
            //cout<<sitoi<<" sdfs "<<2*sitoi<<"  sadasdadasd"<<endl;
            /*
            void str2int(int &int_temp,const string &string_temp)
            {
                stringstream stream(string_temp);
                stream>>int_temp;
            }
            */
            pushInt(sitoi); //吧数字压入到数字栈
        }

        //处理字符压入栈还是出来运算
        //取出运算符
        char sc=s[found];       //string支持这种方式访问
        s=s.substr(found+1, s.length());
        //cout<<sc<<" ddddd "<<s<<endl;
        //判断是不是操作符
        if(isOperator(sc))
        {
            //是操作符那么入栈
            //入栈之前和站内原有的字符比较
            char bijiao=isFirst(tailCharSt->c, sc);
            if(bijiao == '<')
                //c1小于c2优先级,直接入栈
                pushChar(sc);
            else if(bijiao == '=')
                popChar();  //括号匹配,直接把括号去掉
            else if(bijiao == '>')
            {
                //c1的优先级比较大,那么进行c1的运算符操作
                int b=popInt(); //出后面那个数字
                int a=popInt(); //出前面那个数字
                char o=popChar();   //前面那个优先级搞的字符进行操作
                //进行字符操作
                int c=doOperator(a, o, b);
                //吧数字放回去
                pushInt(c);
                //吧优先级低的字符压入栈
                //pushChar(sc);
                //这里不能把符号加入,因为进行了运算,符号要等在数值后面添加
                //我们得吧sc加回到string中
                s=sc+s; //这一步很重要要点!!2014年8月5日10:52:59
                //cout<<"ok?"<<endl;
            }//else if(bijiao == '>')
        }//if(isOperator(sc))
    }//while(s != "" || tailCharSt->c == '#')

    //返回数字栈的栈顶元素,就是结果
    return tailIntSt->i;
}


/********************************************************************************/
int main()
{
    string test;
    cin>>test;
    cout<<result(test)<<endl;

    system("pause");
    return 0;
}

//初步完成时间2014年8月3日17:14:11
/********************************************************************************/



测试表达式:

(10-9)*24+128/4#


结果:

56


PS:这次的表达式求值比上两次有有点改进,就是不是仅仅停留在0~9数字之间的表达式求值了,而是比较大的数了,比如128比如10比如24,不限制位数。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值