/**
* 功能:表达式求值
* 时间: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,不限制位数。