这几天学习《算法》这本书,第一章后面的习题,关于算术表达式,前序表达式,中序表达式,后序表达式的实现,我学习了两天,不断的编写调试,初步实现了具体功能。首先
中序表达式 | ((1+2)*((3-4)*(5-6)))) | |
后序表达式 | 12+34-56-** | |
前序表达式 | *+12*-34-56 |
中序表达式是我们人类习惯使用的表达,但是,计算机很难使用。计算机一般是采用栈的技术来实现的,要么转换为前序表达式,要么转换为后序表达式。
例如以后序表达式为例,12+34-56-**
首先2与1+等于3,变成334-56-**
然后4-3变成,3156-**
然后6-5变成,311**
然后1*1,变成31*
最后等于3
即从右至左取数,直到取出一个运算符,将刚取出的紧挨着运算符的两个操作数按运算符进行计算,结果回填至运算符。重复该步骤,直到最后只剩下一个字符串则剩下的字符串即为结果。
后序表达式的字符串扫描方式正好和前序相反,是从左往右扫描,规则类似。
中序表达式转后序表达式步骤
1、输入字符串,如“2*3/(2-1)+3*(4-1)”
2、从字符串中取出下一个字符
2.1.如果是操作数,则直接输出
2.2.如果是“(”,压入栈中
2.3.如果是运算符但不是“(”,“)”,则不断循环进行以下处理
2.3.1.如果栈为空,则此运算符进栈,结束此步骤
2.3.2.如果栈顶是“(”,则此运算符进栈,结束此步骤
2.3.2.如果此运算符与栈顶优先级相同或者更高,此运算符进栈,结束此步骤
2.3.4.否则,运算符连续出栈,直到满足上述三个条件之一,然后此运算符进栈
2.4、如果是“)”,则运算符连续出栈,直到遇见“(”为止,将“(”出栈且丢弃之
3、如果还有更多的字符串,则转到第2步
4、不在有未处理的字符串了,输出栈中剩余元素
程序源码为:
package sanzhang; import ref.Stack; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class exe6 { public static void main(String[] args) { // TODO Auto-generated method stub //String strold="2*3/(2-1)+3*(4-1)"; String strold="((1+2)*((3-4)*(5-6)))"; //String strold="(1+2)+(8/4)"; //String strold="3*(2-1)*3*(6/3)"; //存放栈 Stack<String> oper=new Stack<String>(); //转换成字符型数组 char ch[]=strold.trim().toCharArray(); //定义一个字符串数组 String str[]=new String[ch.length]; //存放结果数组 List<String> list=new ArrayList<String>(); //将原来表达式字符数组转换成字符串数组 for(int i=0;i<ch.length;i++) { str[i]=String.valueOf(ch[i]); } //逐个判断字符串 for(int i=0;i<str.length;i++) { //当输入的是操作数时,直接添加到结果表达式后 if(str[i].matches("^[1-9]\\d*$"))//正则表达式 { list.add(str[i]); } else //当输入的是左括号的时候,直接入栈 if(str[i].equals("(")) { oper.push(str[i]); } //如果是右括号,则运算符连续出栈,直到遇见左括号为止,左括号出栈且丢弃它 else if(str[i].equals(")")) { while(oper.size()> 0 && !oper.peek().equals("(")) { //运算符连续出栈 String ss = oper.pop(); list.add(ss); } //直到遇到左括号,并丢弃之 oper.pop(); } //如果为操作符+-*/等 else { //如果栈为空,直接进栈 if(oper.isEmpty()) { oper.push(str[i]); continue; } else //如果栈顶为左括号,运算符进栈 if(oper.peek().equals("(")) { oper.push(str[i]); continue; } else //如果此运算符与栈顶优先级相同或更高,此运算符进栈,结束此步骤,取下一个字符, if(priority(str[i])>priority(oper.peek())) { oper.push(str[i]); } //如果三个条件均不满足,则连续出栈,直到满足其中三个一个,再进栈 else { do { list.add(oper.pop()); } while(!(oper.isEmpty()||oper.peek().equals("(")||priority(str[i])>priority(oper.peek()))); oper.push(str[i]); } } } //如果此时栈非空,全部输出 while(!oper.isEmpty()) { list.add(oper.pop()); } //对结果动态数组遍历 for(int i=0;i<list.size();i++) { System.out.print(list.get(i)+""); } System.out.println(); //输出计算结果 System.out.println(calcauteAfterExpression(list)); } // 返回运算符的优先级 public static int priority(String temp) { char ch=temp.charAt(0); int pri; switch (ch) { case ‘+‘: pri = 1; break; case ‘-‘: pri = 1; break; case ‘*‘: pri = 2; break; case ‘/‘: pri = 2; break; default: pri = 0; break; } return pri; } //判断是否为运算符 public static boolean IsOperator(String temp) { if(temp.equals("+")||temp.equals("-")||temp.equals("*")||temp.equals("/")) return true; return false; } /// <summary> /// 计算后序表达式 /// </summary> //将操作数动态数组作为参数进行传递 public static int calcauteAfterExpression(List<String> newExpression ) { int result=0 ; if (newExpression.size() > 1) { int i = 0; for (i = 0; i < newExpression.size(); i++) { //首先判断是否为运算符 if (IsOperator(newExpression.get(i))) { //取运算符左边与运算符次左边的进行运算 if (newExpression.get(i).equals("+")) { result =Integer.parseInt(newExpression.get(i-2))+Integer.parseInt(newExpression.get(i-1)); } else if (newExpression.get(i).equals("-")) { result =Integer.parseInt(newExpression.get(i-2))-Integer.parseInt(newExpression.get(i-1)); } else if (newExpression.get(i).equals("*")) { result =Integer.parseInt(newExpression.get(i-2))*Integer.parseInt(newExpression.get(i-1)); } else if (newExpression.get(i).equals("/")) { result =Integer.parseInt(newExpression.get(i-2))/Integer.parseInt(newExpression.get(i-1)); } break; } } //第一轮计算完毕,将运算符所在的位置用计算得到的结果进行替换,并把运算符左边的元素和次左边的元素移除 newExpression.set(i, String.valueOf(result)); newExpression.remove(i-1); newExpression.remove(i-2); //再进行递归运算 calcauteAfterExpression(newExpression); } //直到运算符全部用完,只剩下最后一个操作数,即为我们所需要的值 return Integer.parseInt(newExpression.get(0)); } }
中序表达式转前序表达式步骤
1、反转输入字符串,如“2*3/(2-1)+3*(4-1)” 反转后为“ )1-4(*3+)1-2(/3*2”,
2、从字符串中取出下一个字符
2.1.如果是操作数,则直接输出
2.2.如果是“)”,压入栈中
2.3.如果是运算符但不是“(”,“)”,则不断循环进行以下处理
2.3.1.如果栈为空,则此运算符进栈,结束此步骤
2.3.2.如果栈顶是“)”,则此运算符进栈,结束此步骤
2.3.2.如果此运算符与栈顶优先级相同或者更高,此运算符进栈,结束此步骤
2.3.4.否则,运算符连续出栈,直到满足上述三个条件之一,然后此运算符进栈
2.4、如果是“(”,则运算符连续出栈,直到遇见“)”为止,将“)”出栈且丢弃之
3、如果还有更多的字符串,则转到第2步
4、不在有未处理的字符串了,输出栈中剩余元素
5、再次反转字符串得到最终结果
package sanzhang; import java.util.*; public class exe7 { public static void main(String[] args) { // TODO Auto-generated method stub //String strold="2*3/(2-1)+3*(4-1)"; String strold="((1+2)*((3-4)*(5-6)))"; Stack<String> oper=new Stack<String>(); StringBuffer sb=new StringBuffer();//记录结果表达式 char ch[]=strold.trim().toCharArray(); String str[]=new String[ch.length]; List<String> list=new ArrayList<String>(); for(int i=ch.length-1;i>=0;i--) { list.add(String.valueOf(ch[i])); } //获得反转字符串 for(int j=0;j<str.length;j++) { str[j]=list.get(j); } for(int i=0;i<str.length;i++) { //如果是操作数,直接输出 if(str[i].matches("^[1-9]\\d*$")) { sb.append(str[i]); } //如果是“)”,压入栈中 else if(str[i].equals(")")) { oper.push(str[i]); } //如果是左括号,则运算符连续出栈,直到遇见右括号为止,右括号出栈且丢弃它 else if(str[i].equals("(")) { //右括号 while (oper.size()> 0 && !oper.peek().equals(")")) { String ss = oper.pop(); sb.append(ss); } //右括号出栈且丢弃它 oper.pop(); } else { //如果栈为空,次运算符进栈,结束此步骤,取下一个字符 if (oper.size()== 0) { oper.push(str[i]); } //如果栈顶是“)”,此运算符进栈,结束次步骤,读取下一个字符 else if (oper.peek().toString() == ")") { oper.push(str[i]); } //如果此运算符与栈顶优先级相同或更高,此运算符进栈,结束次步骤,取下一个字符, else if (priority(str[i])>=priority(oper.peek().toString())) { oper.push(str[i]); } //否则,运算符连续出栈,直至满足上述三个条件之一退出此步骤 else { do { String podstr = oper.pop().toString(); sb.append(podstr); } while (!(oper.size() == 0 ||oper.peek().toString() == ")" || priority(str[i])>=priority(oper.peek().toString()))); oper.push(str[i]); } } } while(oper.size()!=0) { sb.append(oper.pop()); } System.out.println(sb.reverse()); } // 返回运算符的优先级 public static int priority(String temp) { char ch=temp.charAt(0); int pri; switch (ch) { case ‘+‘: pri = 1; break; case ‘-‘: pri = 1; break; case ‘*‘: pri = 2; break; case ‘/‘: pri = 2; break; default: pri = 0; break; } return pri; } }
原文:http://liuzhangheng.blog.51cto.com/8792220/1392449