参考:中缀表达式求值问题
一丶中缀表达式求值问题
中缀表达式的求值问题是一个比较常见的问题之一,我们通常在编写程序时,直接写出表达式让编译器去处理,很少去关心编译器是怎么对表达式进行求值的,今天我们来一起了解一下其中具体的原理和过程。
表达式一般来说有三种:前缀表达式、中缀表达式、后缀表达式,其中后缀表达式又叫做逆波兰表达式。中缀表达式是最符合人们思维方式的一种表达式,顾名思义,就是操作符在操作数的中间。而前缀表达式和后缀表达式中操作符分别在操作数的前面和操作数的后面。举个例子:
3+2
这个是最简单的一个中缀表达式。而其等同的前缀表达式形式为+32,后缀表达式形式为32+。
那么一些朋友可能会问既然中缀表达式最符合人类的思维习惯,为什么还需要前缀表达式和后缀表达式?先看一个例子,假如在前面的表达式基础上加一点东西:
3+2*5
此时的表达式很显然,如果进行计算,则先计算2*5,最后计算加法。但是如果需要先计算加法运算呢?则必须加上括号,(3+2)*5。
而如果用后缀表达式来表示,则为 32+5*,那么该表达式的计算顺序为3+2 —> (3+2)*5。
区别就在这里,后缀表达式不需要用括号就能表示出 整个表达式哪部分运算先进行。同理,前缀表达式也是如此。这种表达式正好最符合计算机的处理方式,因为后缀表达式和前缀表达式求值不需要考虑优先级的问题,计算机处理起来便简单很多。
今天我们这里主要讲解中缀表达式和后缀表达式(前缀表达式和后缀表达式很类似,就不做过多赘述),
1.中缀表达式直接求值
对于中缀表达式求值来说,一般最常见的直接解决办法就是利用栈,一个栈用来保存操作数,一个栈用来保存操作符。
为了简便起见,暂时表达式中只考虑简单的+,-,*,/运算,只有圆括号,并且都是整数。
假如有这样一个表达式:((3+5*2)+3)/5+6/4*2+3
对于这样一个表达式,如果让你来设计操作数和操作符进栈的出栈的规则,你会怎么设计?
先不看这么复杂的表达式,考虑一下简单点的,还是前面的3+2*5,那么很显然先进行乘法运算,后进行加法运算,但是由于操作符在操作数中间,所以当一个操作符进操作符栈时,该操作符的两个操作数并没有都进入到操作数栈中,那么如何解决呢?只有在后面一个操作符进操作符栈时,前面的一个操作符所作用的两个操作数才会全部进栈。比如3+2*5,栈的变化过程为:
操作数栈:3 操作数栈:3 操作数栈:3 2
操作符栈:空 操作符栈:+ 操作符栈:+
注意此时遇到操作符“*”,是不是需要弹出操作数栈中的两个操作数进行运算呢,很显然不是,因为乘法运算法比操作符栈的栈顶运算符优先级高,也就是说当前的操作符在“+”前进行运算,那么还需要将当前操作符压栈,则变成:
操作数栈:3 2 操作数栈:3 2 5
操作符栈:+ * 操作符栈:+ *
此时到了表达式的结尾,既然栈顶的操作符的优先级比栈底的操作符的优先级高,那么可以取操作符栈的栈顶操作符和操作数栈的栈顶两个元素进行计算,则得到2*5=10,(注意从操作数栈先弹出的操作数为右操作数)。此时得到10 ,则应该把10继续压到操作数栈中,继续取操作符栈的栈顶操作符,依次进行下去,则当操作符栈为空时表示计算过程完毕,此时操作数栈中剩下的唯一元素便是整个表达式的值。
再换个例子:2*5+3,这个表达式跟前面表达式的结果虽然相同,但是操作数和操作符入栈和出栈的顺序发生了很大变化:
操作数栈:2 操作数栈:2 操作数栈:2 5
操作符栈:空 操作符栈:* 操作符栈:*
此时遇到“+”,而操作符栈的栈顶操作符为“*”,栈顶操作符优先级更高,表示此时可以取操作符栈顶操作符进行运算,那么栈变成:
操作数栈:10 操作数栈:10 3
操作符栈:空 操作符栈:+
后面的过程跟前面一个例子类似。
如果复杂一点,比如包含有括号,连续的乘除法这些怎么处理呢?道理是一样的,对于左括号直接入栈,碰到右括号,则一直将操作符退栈,直到碰到左括号,则括号中的表达式计算完毕。对于连续的乘除法,跟前面例子中处理过程类似。只需要记住一点:只有当前操作符的优先级高于操作符栈栈顶的操作符的优先级,才入栈,否则弹出操作符以及操作数进行计算直至栈顶操作符的优先级低于当前操作符,然后将当前操作符压栈。当所有的操作符处理完毕(即操作符栈为空时),操作数栈中剩下的唯一一个元素便是最终的表达式的值。而操作符的优先级为:+和-优先级是一样的,*和/优先级是一样的,+、-的优先级低于*、/的优先级。
不过需要注意的是在求值之前需要对表达式进行预处理,去掉空格、识别 负号(区分“-”是作为减号还是负号),提取操作数等。
对于“-”的区分,主要判别方法为:
1)若前一个字符为‘(',则必定为负号;
2)若前一个字符为')'或者数字,则必定为减号;
3)若前面一个字符为其他运算符,如*,/,则必定是负号;
3)若前面没有字符,即该字符为表达式的第一个字符,则必定是负号。
也就是说只有一种情况下,”-“是作为减号使用的,就是前一个字符为')'或者数字的时候。
如果判断出“-”是作为负号使用的,这里我采用“#”来代替“-”,并将其作为一种运算(优先级最高)。比如:-3*2
我采取的做法是将"#"入栈,然后当遇到“*”时,由于栈顶操作符为"#",因此取#,然后取操作数栈的栈顶元素(只取一个)进行运算,然后再把结果压栈。
/*2014.5.6 测试环境: mingw*/
#include <iostream>
#include <vector>
#include <stack>
#include <string>
#include <cstdlib>
#include <cctype>
#include <cstring>
using namespace std;
vector<string> preParse(char *str) //对中缀表达式进行预处理,分离出每个token
{
vector<string> tokens;
int len = strlen(str);
char *p = (char *)malloc((len+1)*sizeof(char)); //注意不要用 char *p = (char *)malloc(sizeof(str))来申请空间
int i=0,j=0;
while(i<len) //去除表达式中的空格
{
if(str[i]==' ')
{
i++;
continue;
}
p[j++] = str[i++];
}
p[j]='\0';
j=0;
len = strlen(p);
while(j<len)
{
char temp[2];
string token;
switch(p[j])
{
case '+':
case '*':
case '/':
case '(':
case ')':
{
temp[0] =p[j];
temp[1] = '\0';
token=temp;
tokens.push_back(token);
break;
}
case '-':
{
if(p[j-1]==')'||isdigit(p[j-1])) //作为减号使用
{
temp[0] =p[j];
temp[1] = '\0';
token=temp;
tokens.push_back(token);
}
else //作为负号使用
{
temp[0] ='#';
temp[1] = '\0';
token=temp;
tokens.push_back(token);
}
break;
}
default: //是数字
{
i = j;
while(isdigit(p[i])&&i<len)
{
i++;
}
char *opd = (char *)malloc(i-j+1);
strncpy(opd,p+j,i-j);
opd[i-j]='\0';
token=opd;
tokens.push_back(token);
j=i-1;
free(opd);
break;
}
}
j++;
}
free(p);
return tokens;
}
int getPriority(string opt)
{
int priority;
if(opt=="#")
priority = 3;
else if(opt=="*"||opt=="/")
priority = 2;
else if(opt=="+"||opt=="-")
priority = 1;
else if(opt=="(")
priority = 0;
return priority;
}
void calculate(stack<int> &opdStack,string opt)
{
if(opt=="#") //进行负号运算
{
int opd = opdStack.top();
int result = 0-opd;
opdStack.pop();
opdStack.push(result);
cout<<"操作符:"<<opt<<" "<<"操作数:"<<opd<<endl;
}
else if(opt=="+")
{
int rOpd = opdStack.top();
opdStack.pop();
int lOpd = opdStack.top();
opdStack.pop();
int result = lOpd + rOpd;
opdStack.push(result);
cout<<"操作符:"<<opt<<" "<<"操作数:"<<lOpd<<" "<<rOpd<<endl;
}
else if(opt=="-")
{
int rOpd = opdStack.top();
opdStack.pop();
int lOpd = opdStack.top();
opdStack.pop();
int result = lOpd - rOpd;
opdStack.push(result);
cout<<"操作符:"<<opt<<" "<<"操作数:"<<lOpd<<" "<<rOpd<<endl;
}
else if(opt=="*")
{
int rOpd = opdStack.top();
opdStack.pop();
int lOpd = opdStack.top();
opdStack.pop();
int result = lOpd * rOpd;
opdStack.push(result);
cout<<"操作符:"<<opt<<" "<<"操作数:"<<lOpd<<" "<<rOpd<<endl;
}
else if(opt=="/")
{
int rOpd = opdStack.top();
opdStack.pop();
int lOpd = opdStack.top();
opdStack.pop();
int result = lOpd / rOpd;
opdStack.push(result);
cout<<"操作符:"<<opt<<" "<<"操作数:"<<lOpd<<" "<<rOpd<<endl;
}
}
int evaMidExpression(char *str) //中缀表达式直接求值
{
vector<string> tokens = preParse(str);
int i=0;
int size = tokens.size();
stack<int> opdStack; //存储操作数
stack<string> optStack; //存储操作符
for(i=0;i<size;i++)
{
string token = tokens[i];
if(token=="#"||token=="+"||token=="-"||token=="*"||token=="/")
{
if(optStack.size()==0) //如果操作符栈为空
{
optStack.push(token);
}
else
{
int tokenPriority = getPriority(token);
string topOpt = optStack.top();
int topOptPriority = getPriority(topOpt);
if(tokenPriority>topOptPriority)
{
optStack.push(token);
}
else
{
while(tokenPriority<=topOptPriority)
{
optStack.pop();
calculate(opdStack,topOpt);
if(optStack.size()>0)
{
topOpt = optStack.top();
topOptPriority = getPriority(topOpt);
}
else
break;
}
optStack.push(token);
}
}
}
else if(token=="(")
{
optStack.push(token);
}
else if(token==")")
{
while(optStack.top()!="(")
{
string topOpt = optStack.top();
calculate(opdStack,topOpt);
optStack.pop();
}
optStack.pop();
}
else //如果是操作数,直接入操作数栈
{
opdStack.push(atoi(token.c_str()));
}
}
while(optStack.size()!=0)
{
string topOpt = optStack.top();
calculate(opdStack,topOpt);
optStack.pop();
}
return opdStack.top();
}
int main(int argc, char *argv[])
{
char *str = "((3+5*2)+3)/5+(-6)/4*2+3";
cout<<evaMidExpression(str)<<endl;
return 0;
}
运行结果:
二丶后缀表达式求值
后缀表达式也叫逆波兰表达式,其求值过程可以用到栈来辅助存储。假定待求值的后缀表达式为:6 5 2 3 + 8 * + 3 + *,则其求值过程如下:
1)遍历表达式,遇到的数字首先放入栈中,此时栈如下所示:
2)接着读到“+”,则弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中。
3)读到8,将其直接放入栈中。
4)读到“*”,弹出8和5,执行8*5,并将结果40压入栈中。而后过程类似,读到“+”,将40和5弹出,将40+5的结果45压入栈...以此类推。最后求的值288。
Evaluate the value of an arithmetic expression in Reverse Polish Notation.
Valid operators are +, -, *, /. Each operand may be an integer or another expression.
Some examples: ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6
- 题目大意:给定一个逆波兰表达式,求该表达式的值
- 思路:由于逆波兰表达式本身不需要括号来限制哪个运算该先进行,因此可以直接利用栈来模拟计算:遇到操作数直接压栈,碰到操作符直接取栈顶的2个操作数进行计算(注意第一次取出来的是右操作数),然后再把计算结果压栈,如此循环下去。最后栈中剩下的唯一一个元素便是整个表达式的值
- 实现:
-
class Solution { public: int evalRPN(vector<string> &tokens) { int result = 0; int i; stack<int> opd; //存储操作数 int size = tokens.size(); for(i=0;i<size;i++) { if(tokens[i]=="*") { int rOpd = opd.top(); //右操作数 opd.pop(); int lOpd = opd.top(); //左操作数 opd.pop(); result = lOpd*rOpd; opd.push(result); } else if(tokens[i]=="/") { int rOpd = opd.top(); opd.pop(); int lOpd = opd.top(); opd.pop(); result = lOpd/rOpd; opd.push(result); } else if(tokens[i]=="+") { int rOpd = opd.top(); opd.pop(); int lOpd = opd.top(); opd.pop(); result = lOpd+rOpd; opd.push(result); } else if(tokens[i]=="-") { int rOpd = opd.top(); opd.pop(); int lOpd = opd.top(); opd.pop(); result = lOpd-rOpd; opd.push(result); } else { opd.push(atoi(tokens[i].c_str())); } } return opd.top(); } };
三.中缀表达式如何转为后缀
大部分数据结构教材在讲述 栈的时候都会涉及到中缀表达式转为后缀表达式的问题,因为这个是栈的典型应用之一。因此很多教材上都会利用栈来进行转换,这里我们来讨论一下最常见的两种转换思路和一种简便的验证方法。
- 利用二叉树进行转换
-
由于二叉树本身结构的特殊性,使得我们可以利用它来很轻松地将中缀表达式转变成后缀表达式,事实上,只要根据中缀表达式建立好相应的二叉树之后,直接对二叉树进行前序遍历和后序遍历便可得到前缀表达式和后缀表达式。在利用二叉树来表示表达式时,用叶子节点来存储操作数,用内部节点存储操作符,比如这样一个表达式3*5+5/2+(3+5)*2,表示成二叉树的形式(注意其有等同的其他形式)就是:
其实讲中缀表达式的过程转变成二叉树的形式是一个递归的过程,比如有一个表达式,其对应的的二叉树的根节点必定是优先级最低的操作符(也就是说是整个表达式中最后进行的运算操作),然后再在操作符的左部分中找出最后进行的操作符作为根节点的左孩子,在操作符的右部分中找出最后进行的操作符作为根节点的右孩子,然后知道左部分或者右部分是单纯的操作数,则作为叶子节点,直到整个二叉树建立完毕。
/*
测试环境:VS2010
*/
#include <iostream>
#include <string>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std;
typedef struct node
{
struct node *left;
struct node *right;
char *data;
}BinTree;
char * preProcess(char *str) //预处理,除去空格,将负号替代为#
{
int len = strlen(str);
char *p = (char *)malloc(sizeof(char)*len);
int i=0,j=0;
while(i<len) //去除表达式中的空格
{
if(str[i]==' ')
{
i++;
continue;
}
p[j++] = str[i++];
}
p[j]='\0';
j=0;
len = strlen(p);
while(j<len)
{
if(p[j]=='-')
{
if(!(p[j-1]==')'||isdigit(p[j-1]))) //作为减号使用
{
p[j]='#';
}
}
j++;
}
return p;
}
/*
最后执行的操作符一定是在括号外面,也就是说brackets一定是等于0的,
*/
int indexOfOpt(char *str,int begin ,int end) //寻找最后执行的操作符的下标
{
int i;
int brackets=0; //所在括号层次
int index = -1;
int existAddOrMinus = 0;
int existMulOrDevide = 0;
while(str[begin]=='('&&str[end]==')') //去除最外层的括号
{
begin++;
end--;
}
for(i=begin;i<=end;i++)
{
if(str[i]=='(')
brackets++;
else if(str[i]==')')
brackets--;
else if((str[i]=='+'||str[i]=='-')&&brackets==0)
{
index = i;
existAddOrMinus = 1; //存在加减号
}
else if((str[i]=='*'||str[i]=='/')&&brackets==0&&existAddOrMinus==0)
{
index = i;
existMulOrDevide = 1; //存在乘除号
}
else if(str[i]=='#'&&brackets==0&&existAddOrMinus==0&&existMulOrDevide==0) //用'#'代表负号
{
index = i;
}
}
return index;
}
BinTree * createBinTree(char *str,int begin,int end)
{
BinTree *p =(BinTree *)malloc(sizeof(BinTree));;
int index = indexOfOpt(str,begin,end);
cout<<"index:"<<index<<endl;
if(index==-1) //表示只有操作数了
{
while(str[begin]=='('&&str[end]==')')
{
begin++;
end--;
}
p->data = (char *)malloc(sizeof(end-begin+2));
int i,j=0;
for(i=begin;i<=end;i++)
p->data[j++] = str[i];
p->data[j]='\0';
p->left = NULL;
p->right = NULL;
cout<<"操作数:"<<p->data<<endl;
}
else
{
p->data = (char*)malloc(2);
p->data[0] = str[index];
p->data[1]='\0';
cout<<"操作符:"<<p->data<<endl;
while(str[begin]=='('&&str[end]==')')
{
begin++;
end--;
}
if(str[index]=='#') //是负号
{
p->left = NULL;
}
else
{
p->left = createBinTree(str,begin,index-1);
}
p->right = createBinTree(str,index+1,end);
}
return p;
}
void preOrder(BinTree *root)
{
if(root!=NULL)
{
cout<<root->data<<" ";
preOrder(root->left);
preOrder(root->right);
}
}
void inOrder(BinTree *root)
{
if(root!=NULL)
{
inOrder(root->left);
cout<<root->data<<" ";
inOrder(root->right);
}
}
void postOrder(BinTree *root)
{
if(root!=NULL)
{
postOrder(root->left);
postOrder(root->right);
cout<<root->data<<" ";
}
}
int main(void)
{
char *str = "((3+5*2)+3)/5+(-6)/4*2+3";
char *newStr = preProcess(str);
cout<<newStr<<endl;
BinTree *root=createBinTree(newStr,0,strlen(newStr)-1);
inOrder(root);
cout<<endl;
postOrder(root);
cout<<endl;
system("pause");
return 0;
}
上述代码在VS2010下运行是没有问题的,但是在gcc下编译运行会崩溃,调试了很久没发现原因(如果有哪位朋友知道原因的请麻烦告知)。测试结果:
- 利用栈进行转换
利用栈进行转换的思路其实跟前面直接对中缀表达式求值的过程类似,在这过程中需要一个栈用来保存操作符optStack,需要一个数组用来保存后缀表达式suffix[],然后从头到尾扫描表达式
1)如果遇到操作符,则跟optStack的栈顶操作符比较优先级,如果大于栈顶操作符的优先级,则入栈,否则不断取栈顶操作符加到suffix的末尾,直到栈顶操作符优先级低于该操作符,然后将该操作符入栈;
2)遇到操作数,直接加到suffix的末尾
3)遇到左括号,入栈;
4)遇到右括号,则依次弹出栈顶操作符加到suffix的末尾,直到遇到左括号,然后将左括号出栈。
例:
2.1)规则
中缀表达式a + b*c + (d * e + f) * g,其转换成后缀表达式则为a b c * + d e * f + g * +。
转换过程需要用到栈,具体过程如下:
1)如果遇到操作数,我们就直接将其输出。
2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。
5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
2.2)实例
规则很多,还是用实例比较容易说清楚整个过程。以上面的转换为例,输入为a + b * c + (d * e + f)*g,处理过程如下:
1)首先读到a,直接输出。
2)读到“+”,将其放入到栈中。
3)读到b,直接输出。
此时栈和输出的情况如下:
4)读到“*”,因为栈顶元素"+"优先级比" * " 低,所以将" * "直接压入栈中。
5)读到c,直接输出。
此时栈和输出情况如下:
6)读到" + ",因为栈顶元素" * "的优先级比它高,所以弹出" * "并输出, 同理,栈中下一个元素" + "优先级与读到的操作符" + "一样,所以也要弹出并输出。然后再将读到的" + "压入栈中。
此时栈和输出情况如下:
7)下一个读到的为"(",它优先级最高,所以直接放入到栈中。
8)读到d,将其直接输出。
此时栈和输出情况如下:
9)读到" * ",由于只有遇到" ) "的时候左括号"("才会弹出,所以" * "直接压入栈中。
10)读到e,直接输出。
此时栈和输出情况如下:
11)读到" + ",弹出" * "并输出,然后将"+"压入栈中。
12)读到f,直接输出。
此时栈和输出情况:
13)接下来读到“)”,则直接将栈中元素弹出并输出直到遇到"("为止。这里右括号前只有一个操作符"+"被弹出并输出。
14)读到" * ",压入栈中。读到g,直接输出。
15)此时输入数据已经读到末尾,栈中还有两个操作符“*”和" + ",直接弹出并输出。
至此整个转换过程完成。程序实现代码后续再补充了。
/*2014.5.6 测试环境: mingw*/
#include <iostream>
#include <vector>
#include <stack>
#include <string>
#include <cstdlib>
#include <cctype>
#include <cstring>
using namespace std;
vector<string> preParse(char *str) //对中缀表达式进行预处理,分离出每个token
{
vector<string> tokens;
int len = strlen(str);
char *p = (char *)malloc((len+1)*sizeof(char)); //注意不要用 char *p = (char *)malloc(sizeof(str))来申请空间
int i=0,j=0;
while(i<len) //去除表达式中的空格
{
if(str[i]==' ')
{
i++;
continue;
}
p[j++] = str[i++];
}
p[j]='\0';
j=0;
len = strlen(p);
while(j<len)
{
char temp[2];
string token;
switch(p[j])
{
case '+':
case '*':
case '/':
case '(':
case ')':
{
temp[0] =p[j];
temp[1] = '\0';
token=temp;
tokens.push_back(token);
break;
}
case '-':
{
if(p[j-1]==')'||isdigit(p[j-1])) //作为减号使用
{
temp[0] =p[j];
temp[1] = '\0';
token=temp;
tokens.push_back(token);
}
else //作为负号使用
{
temp[0] ='#';
temp[1] = '\0';
token=temp;
tokens.push_back(token);
}
break;
}
default: //是数字
{
i = j;
while(isdigit(p[i])&&i<len)
{
i++;
}
char *opd = (char *)malloc(i-j+1);
strncpy(opd,p+j,i-j);
opd[i-j]='\0';
token=opd;
tokens.push_back(token);
j=i-1;
free(opd);
break;
}
}
j++;
}
free(p);
return tokens;
}
int getPriority(string opt)
{
int priority;
if(opt=="#")
priority = 3;
else if(opt=="*"||opt=="/")
priority = 2;
else if(opt=="+"||opt=="-")
priority = 1;
else if(opt=="(")
priority = 0;
return priority;
}
vector<string> toSuffix(char *str) //转变为后缀形式
{
vector<string> tokens = preParse(str);
int i=0;
int size = tokens.size();
vector<string> suffix; //存储后缀表达式
stack<string> optStack; //存储操作符
for(i=0;i<size;i++)
{
string token = tokens[i];
if(token=="#"||token=="+"||token=="-"||token=="*"||token=="/")
{
if(optStack.size()==0) //如果操作符栈为空
{
optStack.push(token);
}
else
{
int tokenPriority = getPriority(token);
string topOpt = optStack.top();
int topOptPriority = getPriority(topOpt);
if(tokenPriority>topOptPriority)
{
optStack.push(token);
}
else
{
while(tokenPriority<=topOptPriority)
{
optStack.pop();
suffix.push_back(topOpt);
if(optStack.size()>0)
{
topOpt = optStack.top();
topOptPriority = getPriority(topOpt);
}
else
break;
}
optStack.push(token);
}
}
}
else if(token=="(")
{
optStack.push(token);
}
else if(token==")")
{
while(optStack.top()!="(")
{
string topOpt = optStack.top();
suffix.push_back(topOpt);
optStack.pop();
}
optStack.pop();
}
else //如果是操作数,直接入操作数栈
{
suffix.push_back(token);
}
}
while(optStack.size()!=0)
{
string topOpt = optStack.top();
suffix.push_back(topOpt);
optStack.pop();
}
return suffix;
}
int main(int argc, char *argv[])
{
char *str = "((3+5*2)+3)/5+(-6)/4*2+3";
vector<string> suffix = toSuffix(str);
int size = suffix.size();
for(int i=0;i<size;i++)
cout<<suffix[i]<<" ";
cout<<endl;
return 0;
}
测试结果:
- 简便验证办法
最后一种办法可以很快速地求出中缀表达式对应的前缀表达式和后缀表达式,就是添括号去括号法。
比如有表达式: (3+5*2)-2*3
先对每一个小部分添加括号: ((3+(5*2))-(2*3))
然后将每个操作符放到括号后面:((3(52)*)+(23)*)-
然后去括号:352*+23*-
便得到了后缀表达式,前缀表达式类似(只需把操作符放到括号前面即可)。