中缀表达式转换成后缀表达式并求值

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中缀表达式转换成后缀表达式并求值相关的知识,希望对你有一定的参考价值。

算法:

中缀表达式转后缀表达式的方法:
1.遇到操作数:直接输出(添加到后缀表达式中)
2.栈为空时,遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
6.最终将栈中的元素依次出栈,输出。
例如
a+b*c+(d*e+f)*g ----> abc*+de*f+g*+

遇到a:直接输出:
后缀表达式:a
堆栈:空

遇到+:堆栈:空,所以+入栈
后缀表达式:a
堆栈:+
遇到b: 直接输出
后缀表达式:ab
堆栈:+
遇到*:堆栈非空,但是+的优先级不高于*,所以*入栈
后缀表达式: ab
堆栈:*+
遇到c:直接输出
后缀表达式:abc
堆栈:*+
遇到+:堆栈非空,堆栈中的*优先级大于+,输出并出栈,堆栈中的+优先级等于+,输出并出栈,然后再将该运算符(+)入栈
后缀表达式:abc*+
堆栈:+
遇到(:直接入栈
后缀表达式:abc*+
堆栈:(+
遇到d:输出
后缀表达式:abc*+d
堆栈:(+
遇到*:堆栈非空,堆栈中的(优先级小于*,所以不出栈
后缀表达式:abc*+d
堆栈:*(+
遇到e:输出
后缀表达式:abc*+de
堆栈:*(+
遇到+:由于*的优先级大于+,输出并出栈,但是(的优先级低于+,所以将*出栈,+入栈
后缀表达式:abc*+de*
堆栈:+(+
遇到f:输出
后缀表达式:abc*+de*f
堆栈:+(+
遇到):执行出栈并输出元素,直到弹出左括号,所括号不输出
后缀表达式:abc*+de*f+
堆栈:+
遇到*:堆栈为空,入栈
后缀表达式: abc*+de*f+
堆栈:*+
遇到g:输出
后缀表达式:abc*+de*f+g
堆栈:*+
遇到中缀表达式结束:弹出所有的运算符并输出
后缀表达式:abc*+de*f+g*+
堆栈:空

例程:

这是我自己写的一个简单的中缀表达式求值程序,简单到只能计算10以内的数,支持+-*/()运算符。

复制代码
#include <stack>

using namespace std;

bool IsOperator(char ch)

char ops[] = "+-*/";
for (int i = 0; i < sizeof(ops) / sizeof(char); i++)

if (ch == ops[i])
return true;

return false;


//////////////////////////////////////////////////////////////////////////
// 比较两个操作符的优先级
int Precedence(char op1, char op2)

if (op1 == \'(\')

return -1;


if (op1 == \'+\' || op1 == \'-\')

if (op2 == \'*\' || op2 == \'/\')

return -1;

else

return 0;



if (op1 == \'*\' || op1 == \'/\')

if (op2 == \'+\' || op2 == \'-\')

return 1;

else

return 0;




//////////////////////////////////////////////////////////////////////////
// 中缀表达式转换成后缀表达式
void inFix2PostFix(char* inFix, char* postFix)

int j = 0, len;
char c;
stack<char> st;

len = strlen(inFix);

for (int i = 0; i < len; i++)

c = inFix[i];

if (c == \'(\')
st.push(c);
else if (c == \')\')

while (st.top() != \'(\')

postFix[j++] = st.top();
st.pop();

st.pop();

else

if (!IsOperator(c))
st.push(c);
else

while (st.empty() == false
&& Precedence(st.top(), c) >= 0)

postFix[j++] = st.top();
st.pop();

st.push(c);




while (st.empty() == false)

postFix[j++] = st.top();
st.pop();

postFix[j] = 0;


//////////////////////////////////////////////////////////////////////////
// 后缀表达式求值程序
double postFixEval(char* postFix)

stack<char> st;
int len = strlen(postFix);
char c;

for (int i = 0; i < len; i++)

c = postFix[i];
if (IsOperator(c) == false)

st.push(c - \'0\');

else

char op1, op2;
int val;

op1 = st.top();
st.pop();
op2 = st.top();
st.pop();

switch (c)

case \'+\':
val = op1 + op2;
break;
case \'-\':
val = op2 - op1;
break;
case \'*\':
val = op1 * op2;
break;
case \'/\':
val = op2 / op1;
break;

st.push(val);



return st.top();


int _tmain(int argc, _TCHAR* argv[])

char inFix[100];
char postFix[100];
double val;

while (1)

printf("enter an expression:");
gets_s(inFix);
if (strlen(inFix) == 0)
continue;

printf("\\n%s = ", inFix);
inFix2PostFix(inFix, postFix);
printf("%s = ", postFix);
val = postFixEval(postFix);
printf("%.3f\\n", val);


return 0;
参考技术A 中缀表达式转换成后缀表达式并求值
算法:
中缀表达式转后缀表达式的方法:
1.遇到操作数:直接输出(添加到后缀表达式中)
2.栈为空时,遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
6.最终将栈中的元素依次出栈,输出。
例如
a+b*c+(d*e+f)*g ----> abc*+de*f+g*+
遇到a:直接输出:
后缀表达式:a
堆栈:空
遇到+:堆栈:空,所以+入栈
后缀表达式:a
堆栈:+
遇到b: 直接输出
后缀表达式:ab
堆栈:+
遇到*:堆栈非空,但是+的优先级不高于*,所以*入栈
后缀表达式: ab
堆栈:*+
遇到c:直接输出
后缀表达式:abc
堆栈:*+
遇到+:堆栈非空,堆栈中的*优先级大于+,输出并出栈,堆栈中的+优先级等于+,输出并出栈,然后再将该运算符(+)入栈
后缀表达式:abc*+
堆栈:+
遇到(:直接入栈
后缀表达式:abc*+
堆栈:(+
遇到d:输出
后缀表达式:abc*+d
堆栈:(+
遇到*:堆栈非空,堆栈中的(优先级小于*,所以不出栈
后缀表达式:abc*+d
堆栈:*(+
遇到e:输出
后缀表达式:abc*+de
堆栈:*(+
遇到+:由于*的优先级大于+,输出并出栈,但是(的优先级低于+,所以将*出栈,+入栈
后缀表达式:abc*+de*
堆栈:+(+
遇到f:输出
后缀表达式:abc*+de*f
堆栈:+(+
遇到):执行出栈并输出元素,直到弹出左括号,所括号不输出
后缀表达式:abc*+de*f+
堆栈:+
遇到*:堆栈为空,入栈
后缀表达式: abc*+de*f+
堆栈:*+
遇到g:输出
后缀表达式:abc*+de*f+g
堆栈:*+
遇到中缀表达式结束:弹出所有的运算符并输出
后缀表达式:abc*+de*f+g*+
堆栈:空

例程:
这是我自己写的一个简单的中缀表达式求值程序,简单到只能计算10以内的数,支持+-*/()运算符。

#include <stack>

using namespace std;

bool IsOperator(char ch)

char ops[] = "+-*/";
for (int i = 0; i < sizeof(ops) / sizeof(char); i++)

if (ch == ops[i])
return true;

return false;


//////////////////////////////////////////////////////////////////////////
// 比较两个操作符的优先级
int Precedence(char op1, char op2)

if (op1 == '(')

return -1;


if (op1 == '+' || op1 == '-')

if (op2 == '*' || op2 == '/')

return -1;

else

return 0;



if (op1 == '*' || op1 == '/')

if (op2 == '+' || op2 == '-')

return 1;

else

return 0;




//////////////////////////////////////////////////////////////////////////
// 中缀表达式转换成后缀表达式
void inFix2PostFix(char* inFix, char* postFix)

int j = 0, len;
char c;
stack<char> st;

len = strlen(inFix);

for (int i = 0; i < len; i++)

c = inFix[i];

if (c == '(')
st.push(c);
else if (c == ')')

while (st.top() != '(')

postFix[j++] = st.top();
st.pop();

st.pop();

else

if (!IsOperator(c))
st.push(c);
else

while (st.empty() == false
&& Precedence(st.top(), c) >= 0)

postFix[j++] = st.top();
st.pop();

st.push(c);




while (st.empty() == false)

postFix[j++] = st.top();
st.pop();

postFix[j] = 0;


//////////////////////////////////////////////////////////////////////////
// 后缀表达式求值程序
double postFixEval(char* postFix)

stack<char> st;
int len = strlen(postFix);
char c;

for (int i = 0; i < len; i++)

c = postFix[i];
if (IsOperator(c) == false)

st.push(c - '0');

else

char op1, op2;
int val;

op1 = st.top();
st.pop();
op2 = st.top();
st.pop();

switch (c)

case '+':
val = op1 + op2;
break;
case '-':
val = op2 - op1;
break;
case '*':
val = op1 * op2;
break;
case '/':
val = op2 / op1;
break;

st.push(val);



return st.top();


int _tmain(int argc, _TCHAR* argv[])

char inFix[100];
char postFix[100];
double val;

while (1)

printf("enter an expression:");
gets_s(inFix);
if (strlen(inFix) == 0)
continue;

printf("\n%s = ", inFix);
inFix2PostFix(inFix, postFix);
printf("%s = ", postFix);
val = postFixEval(postFix);
printf("%.3f\n", val);


return 0;

波兰式与逆波兰式的转换和表达式求值


一、前言

逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。

二、表达式

1.中缀表达式

1.1 定义

中缀表达式就是我们最熟悉的一种表达式:1+2,3(3+4),1+23+6,...等都是中缀表示法。对于人们来说,也是最直观的一种求值方式,先算括号里的,
然后算乘除,最后算加减,但是,计算机处理中缀表达式却并不方便,故引出了前缀和后缀。中缀表达式得名于它是由相应的语法树的中序遍历的结果得到的。

2.前缀表达式

2.1 定义

前缀表达式又叫做波兰式。同样的道理,表达式的前缀表达式是由相应的语法树的前序遍历的结果得到的。

1 + 2 * (3 - 4) - 5 * 6的前缀表达式为- + 1 * 2 - 3 4 * 5 6

2.2 求值

由前缀表达式求出结果有下面两种思路:

  1. 从左至右扫描表达式,如果一个操作符后面跟着两个操作数时,则计算。然后将结果作为操作数替换(这个操作符和两个操作数), 重复此步骤,直至所有操作符处理完毕。如- + 1 * 2 - 3 4 * 4 5,扫描到- 3 4时,会计算3 - 4 = -1,表达式变成:- + 1 * 2 -1 * 5 6继续扫描到* 2 -1,计算2 * -1 = -2,表达式变成:- + 1 -2 * 5 6,继续+ 1 -2,依此类推。
  2. 由1知,要多遍扫描表达式,比较复杂,我们可以用一个栈S来实现计算,扫描从右往左进行,如果扫描到操作数,则压进S,如果扫描到操作符,则从S弹出两个操作数进行相应的操作,并将结果压进S(S出2进1),当扫描结束后,S的栈顶就是表达式结果。

3.后缀表达式

3.1 定义

后缀表达式又叫做逆波兰式。它是由相应的语法树的后序遍历的结果得到的。如1 + 2 * (3 - 4) - 5 * 6的后缀表达式为:1 2 3 4 - * + 5 6 * -

注意:逆波兰记法并不是简单的波兰表达式的反转。因为对于不满足交换律的操作符,它的操作数写法仍然是常规顺序,如,波兰记法“/ 6 3”的逆波兰记法是“6 3 /”而不是“3 6 /”;数字的数位写法也是常规顺序。

3.2 求值

由前缀表达式求出结果十分方便,只需要用一个栈S实现:

  • 扫描从左往右进行,如果扫描到操作数,则压进S,如果扫描到操作符,则从S弹出两个操作数进行相应的操作,并将结果压进S(S出2进1),当扫描结束后,S的栈顶就是表达式结果。
  • 后缀表达式和前缀表达式看起来就像一对逆过程,实际上并不是这样子,因为字符读取的时候都是从左往右的,所以,前缀表达式往往需要用两个栈来计算,其中一个栈用来预处理:将字符串倒序压进栈中。

三、表达式转换

1.中缀表达式转换成后缀表达式

既然中缀表达式对于计算机的运算并不便利,而前缀后缀表达式的计算相对简单方便。因此,找到一种途径将中缀表达式转换成前缀后缀表达式就十分重要。实际上,二者的转换算法看起来也很像一个逆过程。因此,我们着重讨论中缀转后缀。

从理论上讲,已知一棵二叉树的中序遍历序列,要求出它的后序遍历序列是不唯一的,即文法是有多义性的。所以,在这里我们要加上优先级这一限制条件,转换就变得唯一了。

1.1 算法

  • 算法: 中缀表达式转换成后缀表达式.
  • 输入: 中缀表达式串.
  • 输出: 后缀表达式串.
PROCESS BEGIN:
1.从左往右扫描中缀表达式串s,对于每一个操作数或操作符,执行以下操作;
2.IF (扫描到的s[i]是操作数DATA)
      将s[i]添加到输出串中;
3.IF (扫描到的s[i]是开括号‘(‘)
      将s[i]压栈;
4.WHILE (扫描到的s[i]是操作符OP)
      IF (栈为空 或 栈顶为‘(‘ 或 扫描到的操作符优先级比栈顶操作符高)
          将s[i]压栈;
          BREAK;
      ELSE
          出栈至输出串中
5.IF (扫描到的s[i]是闭括号‘)‘)
      栈中运算符逐个出栈并输出,直到遇到开括号‘(‘;
      开括号‘(‘出栈并丢弃;
6.返回第1步
7.WHILE (扫描结束而栈中还有操作符)
      操作符出栈并加到输出串中
PROCESS END

1.2 例子

中缀表达式5 + ((1 + 2) * 4) - 3写作转换成后缀表达式:5 1 2 + 4 * + 3 -

下表给出了该逆波兰表达式从左至右求值的过程,堆栈栏给出了中间值,用于跟踪算法。

输入 操作 堆栈 注释
5 入栈 5
1 入栈 5, 1
2 入栈 5, 1, 2
+ 加法运算 5, 3 1, 2出栈,将结果3入栈
4 入栈 5, 3, 4
* 乘法运算 5, 12 3, 4出栈,将结果12入栈
+ 加法运算 17 5, 12出栈,将结果17入栈
3 入栈 17, 3
- 减法运算 14 17, 3出栈,将结果14入栈

计算完成时,栈内只有一个操作数,这就是表达式的结果:14
上述运算可以重写为如下运算链方法:1 2 + 4 * 5 + 3 -

2.中缀表达式转换成前缀表达式

中缀表达式转换成前缀表达式和中缀表达式转换成后缀表达式十分类似,只需要将扫描方向由前往后变成由后往前,将(改为))改为(

四、END

具体的应用可以见我的另外一篇博客:基于逆波兰表达式实现图形化混合计算器.

以上是关于中缀表达式转换成后缀表达式并求值的主要内容,如果未能解决你的问题,请参考以下文章

PTA中缀表达式转换为后缀表达式并求值 (10 分)

中缀表达式转换为后缀表达式

中缀表达式转换为后缀表达式

中缀表达式求值

中缀表达式求值

将中缀表达式转换为后缀表达式,然后利用栈对表达式求值。