编写一个功能类,实现字符串表达式求值
表达式求值是程序设计语言中很重要的问题,它的实现是栈应用的典型例子,即“算符优先算法”。算术四则运算法则是(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;
}
运行结果