例如:Exp =
a
´
b
+
(c
-
d / e)
´
f
其前缀式:+
´
a b
´
-
c / d e f
前缀式(包含了括号信息)的运算规则为:连续出现的两个操作数和在它们之前且紧靠它们的运算符构成一个最小表达式;唯一地确定了运算顺序。先找操作数,再找运算符。
其后缀式:
a b
´
c d e /
-
f
´
+
后缀式
运算符在式中出现的顺序恰为表达式的运算顺序;
每个运算符和在
它之前出现且
紧靠它的两个操作数构成一个最小表达式;(先找运算符,后找操作数)
从上往下扫描,将操作数入栈,遇到X,将两个操作的结果放在栈,c,d,e进栈,遇到/,将d/e结果入栈。遇到-,将c-d/e的结果入栈,再将f入栈,再遇到X。
如何从表达式得到后缀式??
原表达式
: a + b
´
c
-
d / e
´
f
后缀式
: a b c
´
+ d e / f
´
-
规律:
1) 设立运算符栈和操作数栈;
2) 设表达式的结束符为“#”(优先级低),予设运算符栈的栈底为“#”
3) 若当前字符是操作数,则进操作数栈;
4) 若当前运算符的
优先数高于栈顶运算符,则进栈;
5) 否则,
退出栈顶运算符作相应运算(栈顶运算符发送给后缀式,即发送给
操作数栈);
6) “(”对它之前后的运算符起
隔离作用,“)”可视为自相应左括弧开始的表达式的结束符。
可用以下的图示来说明:
表达式如下进行存储:
首先定义两个栈,分别为操作符栈和操作数栈。其整个过程如下:
测试代码如下
#include <string>
#include <stack>
//#include"bo3-1.c"
#include <iostream>
using namespace std;
int charTonum ( char p1 )
{ //将字符转为数字,以表示其优先级别
int pNum =4;
switch (p1 )
{
case '(' : pNum=0; break ;
case '*' : pNum=1; break ;
case '/' : pNum=1; break ;
case '+' : pNum=2; break ;
case '-' : pNum=2; break ;
case ')' : pNum=3; break ;
case '#' : pNum=4; break ;
}
return pNum ;
}
int highleve ( char p1 ,char p2)
{ //判断优先级
// 在优先级表中进行查找,创建二维的表
int t1 [5][5];
for (int i=0; i <5; i ++)
{
for (int j=0; j <5; j ++)
{
t1 [i ][ j]=0;
}
}
// 依次从高级别到低级别
for (int i=0; i <5; i ++)
{
for (int j= i +1; j <5; j++)
{
t1 [i ][ j]=1; // 上三角形
}
}
// 下三角形
for (int j=0; j <5; j ++)
{
for (int i= j +1; i <5; i++)
{
t1 [i ][ j]=-1; // 三角形
}
}
int ch1 = charTonum( p1 );int ch2= charTonum (p2 );
return t1 [ ch1][ ch2 ];// 查询表格,获得优先级判断的结果
}
void printStack ( stack< char > s1 ) //以正常的顺序将其打印
{
stack <char > onetmp;
while (!s1 . empty()) // 非空的情况,就输出结果
{
onetmp .push ( s1. top ());
s1 .pop (); //并以 # 作为结束符
}
while (!onetmp . empty())
{
cout <<onetmp . top();
onetmp .pop ();
}
}
// 将表达式转为后缀式
char myTrans ( char * str )
{
int Len = strlen( str );
stack <char > stack1;
stack <char > stack2; // 放置操作数和操作符
stack2 .push ( '#'); // 操作符的栈底先放置一个结束符
char Tmp ; //收集每个操作数
char *TT ;
int k1 =0;
for (int i=0; i <Len ; i++)
{
if (str [ i]>= '0' &&str [ i]<= '9' )
{
Tmp =str [ i];
stack1 .push ( Tmp); // 先考虑仅仅一位的数字
// 若是考虑数字的位数是两位以上
//
}
else
{
// 将操作数入栈。对于连续的两个都是操作符呢?
//k1=0;
// 对于操作符,先与操作符的栈顶比较
// 先判断是否是右括弧,若是的话,直接弹出直接左括弧
if (charTonum ( str[ i ])!=3 && charTonum ( str[ i ])!=4)
{
int leve = highleve( stack2 .top (), str[ i ]);//0 表示相同级别,表示 str[i] 更高级,1 表示 stack2更高级
// 对于栈顶是左括弧的情况,强制置 leve=-1;
if (charTonum ( stack2. top ())==0)
{ leve =-1;}
if (leve ==-1) //即将入栈的操作符,级别更高
{
stack2 .push ( str[ i ]);// 将操作符入栈
}
else //相等级别,或者低于
{
stack1 .push ( stack2. top ());// 将操作符栈顶的元素入到操作数的栈中
stack2 .pop (); //出栈
stack2 .push ( str[ i ]);
}
}
else
{
if (charTonum ( str[ i ])==3)// 在这里出错???????
{ // 右括弧,直接弹出到左括弧
while (charTonum ( stack2. top ())!=0)
{
stack1 .push ( stack2. top ());
stack2 .pop ();}
// 将左括弧也弹出
stack2 .pop ();
}
if (charTonum ( str[ i ])==4)
{ // 终止符,直接弹出全部
while (charTonum ( stack2. top ())!=4)
{
stack1 .push ( stack2. top ());
stack2 .pop ();}
}
}
}
}
// 输出结果
printStack (stack1 );
return 0;
}
void main ()
{
/*printf(" 请输入算术表达式(中间值及最终结果要在~之间),并以 # 结束\n");
printf("%c\n",EvaluateExpression());*/
char *str = "1*2+(30-4/5)*6#";
myTrans (str );
}