1.3.10将算术表达式由中序表达式转为后序表达式(algs4)
2017-08-17 21:00
330 查看
前序表达式如何求值
对于一个前序表达式的求值而言,首先要从右至左扫描表达式,从右边第一个字符开始判断,如果当前字符是数字则一直到数字串的末尾再记录下来,如果是运算符,则将右边离得最近的两个“数字串”作相应的运算,以此作为一个新的“数字串”并记录下来。一直扫描到表达式的最左端时,最后运算的值也就是表达式的值。例如,前序表达式“- 1 + 2 3“的求值,扫描到3时,记录下这个数字串,扫描到2时,记录下这个数字串,当扫描到+时,将+右移做相邻两数字串的运算符,记为2+3,结果为5,记录下这个新数字串,并继续向左扫描,扫描到1时,记录下这个数字串,扫描到-时,将-右移做相邻两数字串的运算符,记为1-5,结果为-4,所以表达式的值为-4。中序表达式转换为前序表达式的一般算法
(1) 首先构造一个运算符栈(也可放置括号),运算符(以括号分界点)在栈内遵循越往栈顶优先级不降低的原则进行排列。(2)从右至左扫描中序表达式,从右边第一个字符开始判断:
如果当前字符是数字,则分析到数字串的结尾并将数字串直接输出。
如果是运算符,则比较优先级。如果当前运算符的优先级大于等于栈顶运算符的优先级(当栈顶是括号时,直接入栈),则将运算符直接入栈;否则将栈顶运算符出栈并输出,直到当前运算符的优先级大于等于栈顶运算符的优先级(当栈顶是括号时,直接入栈),再将当前运算符入栈。
如果是括号,则根据括号的方向进行处理。如果是右括号,则直接入栈;否则,遇右括号前将所有的运算符全部出栈并输出,遇右括号后将左右的两括号一起删除。
(3) 重复上述操作(2)直至扫描结束,将栈内剩余运算符全部出栈并输出,再逆序输出字符串。中序表达式也就转换为前序表达式了。
将中序表达式“1+((2+3)*4)-5”转换为前序表达式。
中序表达式 | 前序表达式 | (栈顶)运算符栈(栈尾) | 说明 |
5 | 5 | 空 | 5,是数字串直接输出 |
- | 5 | - | -,栈内无运算符,直接入栈 |
) | 5 | -) | ),直接入栈 |
4 | 5 4 | -) | 4,是数字串直接输出 |
* | 5 4 | -)* | *,栈顶是括号,直接入栈 |
) | 5 4 | - ) * ) | ), 4000 直接入栈 |
3 | 5 4 3 | - ) * ) | 3,是数字串直接输出 |
+ | 5 4 3 | - ) * ) + | +,栈顶是括号,直接入栈 |
2 | 5 4 3 2 | - ) * )+ | 2,是数字串直接输出 |
( | 5 4 3 2+ | - ) * | (,参考① |
( | 5 4 3 2+* | - | (,参考① |
+ | 5 4 3 2+* | -+ | +,优先级大于等于栈顶运算符,直接入栈 |
1 | 5 4 3 2+*1 | -+ | 1,是数字串直接输出 |
空 | 5 4 3 2+*1+- | 空 | 扫描结束,将栈内剩余运算符全部出栈并输出 |
空 | - + 1 * + 2 3 4 5 | 空 | 逆序输出字符串 |
后序表达式如何求值
从左到右扫描表达式,计算方法同前序表达式中序表达式转换为后序表达式的一般算法
1、当输入的是操作数时候,直接输出2、当输入开括号时候,把它压栈
3、当输入的是闭括号时候,先判断栈是否为空,若为空,则发生错误并进行相关处理。若非空,把栈中元素依次出栈输出,直到遇到第一个开括号,若没有遇到开括号,也发生错误,进行相关处理
4、当输入是运算符op(+、-、×、/)时候
a)循环,当(栈非空and栈顶不是开括号and栈顶运算符的优先级不低于输入的运算符的优先级)时,反复操作:将栈顶元素出栈输出
b)把输入的运算符op压栈
5、当中序表达式的符号序列全部读入后,若栈内仍有元素,把他们依次出栈输出。若弹出的元素遇到空括号,则说明不匹配,发生错误,并进行相关处理
例如(a+b)*(c+d)这个式子,依演算法的输出过程如下:
OP | STACK | OUTPUT |
( | ( | - |
a | ( | a |
+ | (+ | a |
b | (+ | ab |
) | - | ab+ |
* | * | ab+ |
( | *( | ab+ |
c | *( | ab+c |
+ | *(+ | ab+c |
d | *(+ | ab+cd |
) | * | ab+cd+ |
- | - | ab+cd+* |
转化算法区别:
将中序式转为前序式,则在读取中序式时是由后往前读取,而左右括号的处理方式相反,其余不变,但输出之前必须先置入堆叠,待转换完成后再将堆叠中的值由上往下读出,如此就是前序表示式。中序表达式 | 2*3/(2-1)+3*(4-1) |
前序表达式 (前缀表达式、波兰式) | +/*23-21*3-41 |
后序表达式 (后缀表达式、逆波兰式) | 23*21-/341-*+ (2321-/341-*+*) |
package _1_3linkedList; import edu.princeton.cs.algs4.Stack; import java.util.Scanner; /*1.3.10将算术表达式由中序表达式转为后序表达式 */ public class InfixToPostfix { public static void main(String[] args) { Stack<Character> operatorStack=new Stack<Character>(); /*类型与下面的数组元素相对应*/ Scanner sc=new Scanner(System.in); String s=sc.nextLine(); char c[]=s.toCharArray(); /*对字符串进行分割或转换为字符数组*/ /*从前往后扫描*/ for(int i=0;i<c.length;i++) { if(c[i]=='(')/*当输入左括号时候,把它压栈*/ operatorStack.push(c[i]); else if(c[i]=='+'||c[i]=='-'||c[i]=='*'||c[i]=='/') { /*当输入是运算符op(+、- 、×、/)时候 * a)循环,当(栈非空and栈顶不是左括号and栈顶运算符的优先级不低于输入的运算符的优先级)时, * 反复操作:将栈顶元素出栈输出 * b)把输入的运算符op压栈 * */ boolean isEmpty; boolean isLeftParen; boolean isLowerOperator=false; isEmpty=operatorStack.isEmpty(); if(!isEmpty) { char cTop=operatorStack.peek(); isLeftParen=(cTop=='('); if(cTop=='+'||cTop=='-'&&c[i]=='*'||c[i]=='/') isLowerOperator=true; if(!(isEmpty||isLeftParen||isLowerOperator)) { for(int j=0;j<operatorStack.size();j++) System.out.print(operatorStack.pop()); } } operatorStack.push(c[i]); }else if(c[i]==')') { /*当输入的是右括号时候,先判断栈是否为空,若为空,则发生错误并进行相关处理。 * 若非空,把栈中元素依次出栈输出,直到遇到第一个左括号,若没有遇到左括号,也发生错误,进行相关处理*/ char pop=operatorStack.pop(); while(pop!='(') { System.out.print(pop); pop=operatorStack.pop(); } }else System.out.print(c[i]); } /* 当中序表达式的符号序列全部读入后,若栈内仍有元素,把他们依次出栈输出 */ for(char ch:operatorStack) System.out.print(ch); } }
2*3/(2-1)+3*(4-1) 2321-/341- *+*
简单版本:
package _1_3linkedList; import java.util.Scanner; /*1.3.10将算术表达式由中序表达式转为后序表达式(未省略括号,以括号代替优先级) * 需要一个操作符栈存储操作符 * */ public class InfixToPostfix { public static void main(String[] args) { Stack<Character> operatorStack = new Stack<Character>(); /*类型与下面的数组元素相对应*/ Scanner sc=new Scanner(System.in); String s=sc.nextLine(); char c[]=s.toCharArray(); /*对字符串进行分割或转换为字符数组*/ for(int i=0;i<c.length;i++) { switch (c[i]) {/*将未省略括号的中序表达式转换为后序表达式 1.遇到左括号时忽略 2.遇到操作符入栈 3.遇到右括号时弹出操作符 4.遇到操作数时直接输出 */ case '(': break; case '+': case '-': case '*': case '/': operatorStack.push(c[i]); break; case ')': System.out.print(operatorStack.pop()); break; default: System.out.print(c[i]); } } } }
(3+(((1+2)/3)*(4+5))) 312+3/45+*+
相关阅读:
“中序表达式”转换为“前序表达式”、“后序表达式”
中序、前序、后序表达式
相关文章推荐
- 《算法(第四版)》 习题:1.3.10 将算术表达式由中序表达式转为后序表达式
- 将算术表达式由中序表达式转为后序表达式
- 算术表达式补全右括号(algs4)
- 将中序表达式转为后序表达式
- 栈::将中序算术运算表达式改成后序算术运算式
- 《算法(第四版)》 1.3.10 中序转后序
- 前缀、中缀、后缀表达式与二叉树的前序、中序、后序遍历
- 中序表达式转换为后序表达式
- 前序 中序 后序 遍历二叉树 - 前缀 中缀 后缀 表达式
- 前缀、中缀、后缀表达式与二叉树的前序、中序、后序遍历
- 前缀、中缀、后缀表达式与二叉树的前序、中序、后序遍历
- 前序 中序 后序 遍历二叉树 - 前缀 中缀 后缀 表达式
- 中序表达式转后序(计算版)
- 前缀、中缀、后缀表达式与二叉树的前序、中序、后序遍历
- 前序 中序 后序 遍历二叉树 - 前缀 中缀 后缀 表达式
- 中序表达式 转为 后序表达式(包含了输出运行的结果)(1310 P102)
- 二叉树构建,先序,中序,后序遍历(以及非递归实现),广度优先遍历
- 采用二叉链表结构实现二叉树,并以递归遍历思想实现二叉树的创建、二叉树的遍历(先序、中序、后序和层次遍历)
- 二叉树——已知二叉树先序,建树,并输出中序、后序,并求树叶数和深度
- PHP实现非递归先序、中序、后序遍历二叉树