1.平时我们所接触到的四则运算都是中序表达式,而要进行编程计算时要考虑符号优先级神马的很麻烦,故通常将其转换为前序表达式或者后序表达式:
- 中序表达式:2*3/(2-1)+3*(4-1)
- 前序表达式:+/*23-21*3-41
- 后序表达式:23*21-/341-*+
2.中序转前序:
1.将中序表达式逆转: )1-4(*3+)1-2(/3*2
2.处理逆转后的字符串:
1.如果是操作数,直接输出;
2.如果是运算符
1.如果是“)”,直接入栈;
2.如果是“(”,连续出栈,直至遇到“(”;
3.如果既不是“)”,也是不是“(”
1.栈空,则入栈;
2.栈顶为“)”,则入栈;
3.如果此时符号优先级>=栈顶元素优先级,则入栈;否则出栈,直到栈中的符号优先级大于此时符号或者栈为空;
3.处理完字符串后,如果栈不为空,将栈中的符号输出; //14-3*12-32*/+
4.然后将字符从左到右遍历,不断的将离符号最近的两个数进行进行运算(比如:912-),直到结尾;(按理论是将该字符串逆转变成前序表达式,然后在从右到左进行处理,后序表达式是从左到右进行处理);
3.程序如下:
我选取的存放前序表达式的数据结构为vector<vector<char> >,主要是为了装某个大于一位数值(比如:562),感觉太麻烦了,欢迎大家批评指正;
#include <iostream>
#include <string>
#include <stack>
#include <vector>
using namespace std;
int StringInt(string &a)
{
return atoi(a.c_str());
}
double CharInt(vector<char> &vec)
{
vector<char>::iterator iter=vec.begin();
double result=0;
for( ; iter!=vec.end(); iter++)
result = result*10 + (*iter-'0');
return result;
}
//1.反转表达式
void Reserve(char *p)
{
if(p==NULL)
return ;
char *q=p;
while(*q!='\0')
q++;
q--;
while(p<q)
{
char temp = *p;
*p=*q;
*q=temp;
p++;q--;
}
}
//2.创建符号优先级
int Getprior(char k)
{
int prior=-1;
switch(k)
{
case '+':
prior=1;
break;
case '-':
prior=1;
break;
case '*':
prior=2;
break;
case '/':
prior=2;
break;
case '(':
prior=0;
break;
case ')':
prior=3;
break;
default:
prior=-1;
break;
}
return prior;
}
//用于计算
double Calculate(int a, int b, char k)
{
double prior=0;
switch(k)
{
case '+':
prior=a+b;
break;
case '-':
prior=a-b;
break;
case '*':
prior=a*b;
break;
case '/':
prior=(double)a/(double)b;
break;
default:
break;
}
return prior;
}
//3.用一个栈来处理符号
bool Getresult(char *p, vector<vector<char> > &vec1) //之所以是一个vector<vector<char> >的数组而不是char,是为了防止某数超出char的范围
{
if(p==NULL)
return false;
vector<char> vec11;
stack<char> sta1; //临时存放符号
while(*p!='\0')
{
if(*p==')')
sta1.push(*p++);
else if(*p=='(')
{
vec11.clear();
while(sta1.top()!=')')
{
vec11.push_back(sta1.top());
vec1.push_back(vec11);
sta1.pop();
}
sta1.pop(); //删除')'
p++;
}
else if(*p<='9' && *p>='0') //表示数字
{
vec11.clear();
while(*p<='9' && *p>='0' && *p!='\0')
{
vec11.push_back(*p++);
}
vec1.push_back(vec11);
}
else if(*p!='(' && *p!=')') //表示其他符号
{
if(sta1.empty())
sta1.push(*p++);
else if(sta1.top()==')')
sta1.push(*p++);
else if(Getprior(sta1.top())==Getprior(*p) || Getprior(*p)>=Getprior(sta1.top()))
sta1.push(*p++);
else if(Getprior(Getprior(*p)<sta1.top()))
{
vec11.clear();
while(!sta1.empty() && (Getprior(*p)<Getprior(sta1.top()))) //易错点2:栈有可能已经空了,并且需要放到前面
{
vec11.push_back(sta1.top());
vec1.push_back(vec11);
sta1.pop();
}
sta1.push(*p++);
}
}
else
return false;
}
while(!sta1.empty()) //易错点3:容易丢掉后面在栈里的东西
{
vec11.clear();
vec11.push_back(sta1.top());
vec1.push_back(vec11);
sta1.pop();
}
//output(vec1);
return true;
}
//4.反转成前序表达式+从右到左遍历=直接从左到右
double Calculate(vector<vector<char> > &vec1)
{
int i=0;
vector<vector<char> >::iterator iterRow=vec1.begin();
double a[50]={0.0};
for( ; iterRow!=vec1.end(); iterRow++)
{
vector<char>::iterator iterCol=iterRow->begin();
if(*iterCol=='+' || *iterCol=='-' || *iterCol=='*' || *iterCol=='/')
{
if(i==2)
{
a[0] = Calculate(a[1],a[0],*iterCol); //注意:先出来的那个是被减数 two-one
i=1;
}
else if(i>2) //表示三个数以上连续一个符号的情况,易错点
{
a[i-2] = Calculate(a[i-1],a[i-2],*iterCol);
i=i-1;
}
}
else
{
a[i++] = CharInt(*iterRow);
}
}
return a[0];
}
void Calculate() //测试
{
char str[]={"2*3/(2-1)+3*(4-1)"};
vector<vector<char> > vec1;
Reserve(str);
Getresult(str, vec1);
double result = Calculate(vec1);
cout<<result<<endl;
}
int main()
{
<span style="white-space:pre"> </span>Calculate();
return 0;
}
参考文献:http://www.cnblogs.com/hsrzyn/archive/2009/12/21/1629274.html