逆波兰式:
(1)如果E是一个变量或常量,则E的后缀式是E本身。
(2)如果E是E1 op E2形式的表达式,这里op是如何二元操作符,则E的后缀式为E1’E2’ op,这里E1’和E2’分别为E1和E2的后缀式。
(3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。(带有括号的整体当作一个数,然后用逆波兰式对内部进行解析,然后与括号外的字符串般的连接)
Eg:
(a+b)*c-(a+b)/e的后缀表达式为:
→((a+b)*c)((a+b)/e)-
→((a+b)c*)((a+b)e/)-
→(ab+c*)(ab+e/)
→ab+c*ab+e/-
算法实现
编辑
将一个普通的中序表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
案例
package tujieDataStruct.mystack;
//import java.time.temporal.IsoFields;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Stack;
/**
* 利用中序 遍历的原理
* 用逆波兰式写的一个计算器(栈的利用)
* 创建人:曹雪坤
* 时间:2016年10月14日-上午11:30:19
* @version 1.0.0
*
*/
public class NiBoLanShi {
public static void main(String[] args) {
String P="5 + ( ( 1 + 2 ) * 4 ) - 3";
String RPN="5 1 2 + 4 * + 3 −";
Stack<String> S2 = NiBoLanShi.GetNiBoLanShi(P);
Stack<Double> num = new Stack<Double>();
for(String s : S2){
//如果是数字直接压入栈num 如果是运算符 取两次在压入栈中
if(NiBoLanShi.isFlag(s)){
Double num1 = num.pop();
Double num2 = num.pop();
Double anser = NiBoLanShi.getAnswer(num1, num2, s);
num.push(anser);
}else{
num.push(new Double(s));
}
}
System.out.println("最后的结果是 "+num.pop());
}
/**
* 注意除法 减法 求余两数之间的顺序
* com.dataStructure
* 方法名:getAnswer
* 创建人:曹雪坤
* 时间:2016年10月14日-下午1:58:03
*/
public static Double getAnswer(Double num1,Double num2,String flag){
Double answer = null;
switch (flag) {
case "+":
answer = num1+num2;
break;
case "-":
answer = num2-num1;
break;
case "*":
answer = num1*num2;
break;
case "/":
answer = num2/num1;
break;
case "%":
answer = num2%num1;
break;
default:
break;
}
return answer;
}
/**
* 得到逆波兰式
* com.dataStructure
* 方法名:GetNiBoLanShi
* 创建人:曹雪坤
* 时间:2016年10月14日-上午11:58:45
*/
public static Stack<String> GetNiBoLanShi(String P){
Stack<String> S1 = new Stack<String>();//临时存储运算符的栈S1
Stack<String> S2 = new Stack<String>();//输入逆波兰式的栈
S1.push("#");
String[] nums = P.split(" ");
String Top = "#";
for(String s:nums){
if(NiBoLanShi.isFlag(s.trim())){
Top = S1.pop().trim();
while(true){
//首先判断是否是"("或")";
//若取出的字符是“(”,则直接送入S1栈顶。
//若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
if(s.equals("(") || s.equals("")){
if(s.equals("(")){
S1.push(Top);
S1.push("(");
}else{
S1.push(Top);
String flag = null;
while(!flag.equals("(")){
flag = S1.pop();
if(!flag.equals("(")){
S2.push(flag);
}
}
}
break;
}else{
//判断s的优先级是否比栈顶元素优先级高 如果高于将s压入S1,否则将S1栈顶弹出压入S2
if(NiBoLanShi.decideTop(s.toString().trim()) > NiBoLanShi.decideTop(Top)){
S1.push(Top);
S1.push(s.trim());
break;
}else{
if(Top.equals("(")){
break;
}else{
S2.push(Top);
Top = S1.pop();
}
}
}
}
}else{
//数字
S2.push(s.trim());
}
}//end of for
String last = S1.pop();
S2.push(last);
String flagLast = S1.pop();
if(!flagLast.equals("#")){
System.out.println("输入的格式问题");
return null;
}else{
return S2;
}
// Iterator<String> iterator = S2.iterator();
// while(iterator.hasNext()){
// System.out.print(iterator.next()+"^^^^");
// }
}//end of method GetNiBoLanShi
/**
* 判断是否为符号
* com.dataStructure
* 方法名:isFlag
* 创建人:曹雪坤
* 时间:2016年10月14日-下午12:06:52
*/
public static boolean isFlag(String flag){
if(flag.equals("*")||flag.equals("/")||flag.equals("%")||flag.equals("+")||flag.equals("-")||flag.equals("(")||flag.equals(")")){
return true;
}else{
return false;
}
}
/**
* 返回符号的优先级
* com.dataStructure
* 方法名:decideTop
* 创建人:曹雪坤
* 时间:2016年10月14日-下午12:14:36
*/
public static int decideTop(String flag){
int top = 0;
switch (flag) {
case "+":
top = 1;
break;
case "-":
top = 1;
break;
case "*":
top = 2;
break;
case "/":
top = 2;
break;
case "%":
top = 1;
break;
case "#":
top = 0;
break;
case "(":
top = 0;
break;
case ")":
top = 0;
break;
default:
break;
}
return top;
}
}