字符串表达式

编写一个功能类,实现字符串表达式求值

表达式求值是程序设计语言中很重要的问题,它的实现是栈应用的典型例子,即“算符优先算法”。算术四则运算法则是(1)先乘除后加减;(2)从左算到右;(3)先括号内,后括号外。

任何一个表达式都是由操作数、运算符和界定符组成的。本例中为了简便起见,操作数采用浮点常数,运算符限于+、-、*、/,界定符限于左右括号。

代码

# include <iostream>
# include <sstream>
# include <string>
# include <stack>
# include <vector>
using namespace std;

class MyExpress
{
    string m_strChars;  //算术字符串
    vector<vector<int> > m_vComp;   //优先级比较矩阵
public :
    MyExpress(string m_strchars,string strComps);
    bool GetUnit(string strExpress, int & pos, string & dest, bool & bOper);    //返回每个操作符或操作数
    char CompareProc(char chStack,char ch); //优先级比较函数
    float Calc(float value1,float value2,char oper);    //操作数运算函数
    float Process(string strExpress);   //表达式处理函数
};
//构造函数:用 m_strChars封装运算符内容,二维向量m_vComp描述算符间优先运算级,通过在构造函数中传入字符串strComps并解析完成的
MyExpress::MyExpress(string m_strChars, string strComps):m_vComp(m_strChars.length()-1,vector<int>(m_strChars.length()))
{
    this->m_strChars = m_strChars;
    //根据字符串创建比较矩阵
    istringstream in(strComps);
    for (int i = 0; i < m_vComp.size() - 1; i++)
    {
        for (int j = 0; j < m_strChars.length(); j++)
        {
            in >> m_vComp[i][j];
        }
    }
}
/*
字符串表达式处理主函数process
主要定义了两个栈,一个是操作数栈,一个是算符栈。
当前读取算符与算符栈顶的算符进行优先级比较,若当前算符的优先级大,则把该算符压入算符栈。
若当前算符优先级小,则在算符中弹出该算符,在操作数栈中连续弹出两个操作数,运算结束后把结果压入操作数栈。
*/

float MyExpress::Process(string strExpress) //表达式处理函数
{
    string str = "(" + strExpress + ")";
    strExpress = str;
    stack<float> opnum; //操作数栈
    stack<float> optr;  //操作符栈
    int pos = 0;
    string dest = "";
    bool bOper = false;
    while (true)
    {
        bool bRet = GetUnit(strExpress,pos,dest,bOper);
        if (!bRet) break;
        if (!bOper) //若是操作数直接进栈
        {
            float value;
            istringstream is(dest);
            is >> value;
            opnum.push(value);
        }
        else//若是操作符
        {
            char ch_oper = dest.at(0);
            char result;
            if (optr.empty())
                result = '<';
            else
                result = CompareProc(optr.top(), ch_oper);
            switch (result)
            {
            case '<':
                optr.push(ch_oper); break;
            case '>':
                char ch_oper2 = optr.top(); optr.pop();
                float value1 = opnum.top(); opnum.pop();
                float value2 = opnum.top(); opnum.pop();
                float value = Calc(value1, value2, ch_oper2);

                opnum.push(value);
                if (ch_oper != ')') //若操作符不是”)“
                    optr.push(ch_oper);
                else//若是")",则逆向计算,直到遇到"("为止
                {
                    ch_oper2 = optr.top();
                    while (ch_oper2 != '(')
                    {
                        float value1 = opnum.top(); opnum.pop();
                        float value2 = opnum.top(); opnum.pop();
                        float value = Calc(value1, value2, ch_oper2);

                        opnum.push(value);
                        optr.pop();
                        ch_oper2 = optr.top();
                    }
                    optr.pop();
                }
                break;
            }
        }
    }//while(ture)
    return opnum.top();
}

/* 
获得操作数串或操作符串函数GetUnit
例如strExpress = "12.5+3",从字符串中第pos位开始,先获取第0位字符"1",
看他是否在算符集m_strChar=" + - * / ( ) "中,很明显”1“不再该字符集中,
那么”1“开头的肯定是操作数,到遇到算符时就结束了,因此只要从0位开始查找到第一个属于算符的位置
就得到操作数的结束位置end=4,第4位字符是‘+’,属于算符集中的字符,“+”一定是运算符
*/
bool MyExpress::GetUnit(string strExpress, int& pos, string& dest, bool& bOper)//返回每个操作符或操作数字符串
{
    if (pos >= strExpress.length())
        return false;
    bOper = false;  //默认是操作数标识
    dest = strExpress.substr(pos,1);
    if (m_strChars.find(dest) != string::npos)//若是操作符
    {
        bOper = true;   //置操作标识为真
        pos += 1;   //搜索下一个操作数或者操作符起始位置
    }
    else//获取操作数
    {
        int end = strExpress.find_first_of(m_strChars,pos+1);
        if (end != string::npos)
        {
            dest = strExpress.substr(pos,end-pos);
            pos = end;
        }
        else
        {
            dest = strExpress.substr(pos,strExpress.length()-pos);
            pos = strExpress.length();
        }
    }
    return true;
}

char MyExpress::CompareProc(char chStack, char ch) //优先级比较函数,chStack算符栈顶运算符,ch当前获得单元运算符
{
    if (chStack == '#')return'<';
    int pos1 = m_strChars.find(chStack);
    int pos2 = m_strChars.find(ch);
    return (m_vComp[pos1][pos2]==1?'>':'<');
}


float MyExpress::Calc(float value1, float value2, char oper)    //操作数运算函数
{
    float value = 0.0f;
    switch(oper)
    {
        case '+':
            value = value1 + value2; break;
        case '-':
            value = value1 - value2; break;
        case '*':
            value = value1 * value2; break;
        case '/':
            value = value1 / value2; break;
    }
    return value;
}

//测试函数main()
int main()
{
    string m_strChars = "+=*/()";
    string strComps = "";
    strComps = strComps + "1 1 0 0 0 1 " + "1 1 0 0 0 1 " + "1 1 1 1 0 1 " + "1 1 1 1 0 1 " + "0 0 0 0 0 0";//最后字串没有空格
    MyExpress obj(m_strChars,strComps);
    string str = "(((1+2*3)+4*5)*6)";
    float value = obj.Process(str);
    cout << "表达式的值" << str << "=" << value << endl;
    return 0;
}

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值