首先,大家可以看看数据结构与算法,或者大话数据结构之类的堆栈的章节,知道中缀表达式、后缀表达式概念及使用stack转换及计算的原理再看程序实现比较好。我提一下,
除了可以用stack来将中缀表达式转换成后缀表达式,也可以用二叉树来令前缀表达式、中缀表达式、后缀表达式相互转换,
具体可以看这个例子:
很简单对吧?但是如何构建一颗二叉树是一个大问题。这个问题留待二叉树章节再讨论。
网上也有一些copy转载的使用stack转换后缀表达式的介绍,如下:
算法描述:
将中缀表达式转换为等价的后缀表达式的过程要使用一个栈放“(”,具体可以按照下面的方式进行。
(1)从左到右依次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。
(2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号内的操作处理完毕。
(3)如果遇到的是操作符,则将该操作符和操作符栈顶元素比较:
1、当所遇到的操作符的优先级小于或等于栈顶元素的优先级时,则取 出栈顶元素放入后缀表达式,并弹出该栈顶元素,反复执行直到当前操作符的优先级大于栈顶元素的优先级小于;
2、当所遇到的操作符的优先级大于栈顶元素的优先级的时则将它压入栈中。
在这里我简单说一说自己的观点,遇到小括号大括号之类的,不能简单按照第二点要求来处理,应该将小括号里面的字符串提取出来,自行处理成为一个后缀表达式,然后添加到当前后缀表达式的栈里面,假如遇到小括号嵌套小括号之类的情况,那么只能用递归处理了。总能找到没有小括号的一个子表达式。
所以网上的关于小括号的做法,除了遇到 1+1-1这类简单情况适用外,其他情况不适用。
下面我将一个转换简单四则运算(不包含小括号,只包含小数,整数,加减乘除)的中缀表达式转化成后缀表达式,并且计算结果的算法:
package Chacter4;
import java.util.ArrayList;
import java.util.Stack;
import Easis.Common.StringUtil;
public class hzBDS {
public static void main(String[] args){
System.out.println("该中缀表达式对应的后缀表达式为:");
hzBDS hz=new hzBDS();
String myOpStr1="9+12/2+3-4*7";
myOpStr1="4*7+5-10*1.2+3.6+1.4-1.2*1.2+1*5";
myOpStr1="3*3*4/2+4/2/1*3-1*2*3+7-2+3";
Stack<CaculateUnit> myStack=hz.simple_getHZBDS(myOpStr1);
hz.debug(myStack);
float res=hz.caculateHZS(myStack);
System.out.println("");
System.out.println("计算结果为:"+res);
}
/**
* 获得简单四则运算的后缀表达式,这里指,没有小括号,只包含小数,整数,加减乘除的中缀表达式。
* */
public Stack<CaculateUnit> simple_getHZBDS(String originStr){
if(originStr==null||originStr.trim().length()<=0){
return null;
}
ArrayList<CaculateUnit> _arr=new ArrayList<CaculateUnit>();
StringBuilder sb_res=new StringBuilder();
int preLoc=-1;
int currentLoc=0;
String res=originStr.trim();
Stack<CaculateUnit> _opStack=new Stack<CaculateUnit>();
Stack<CaculateUnit> _ResultStack=new Stack<CaculateUnit>();
for(int i=0;i<res.length();i++){
char c1=res.charAt(i);
if(c1=='+'||c1=='-'||c1=='*'||c1=='/'){
if(preLoc!=-1){
String str_op=res.substring(preLoc, i);
CaculateUnit cOP=new CaculateUnit();
cOP.operationNumber=StringUtil.toFloat(str_op);
cOP.type=CaculateType.Number;
_ResultStack.push(cOP);
}
else if(preLoc==-1&&i>0){
preLoc=0;
String str_op=res.substring(preLoc, i);
CaculateUnit cOP=new CaculateUnit();
cOP.operationNumber=StringUtil.toFloat(str_op);
cOP.type=CaculateType.Number;
_ResultStack.push(cOP);
}
preLoc=i+1;
CaculateUnit cUnit=new CaculateUnit();
cUnit.operationNumber=0.0f;
if(c1=='+'){
cUnit.type=CaculateType.PLUS;
}
else if(c1=='-'){
cUnit.type=CaculateType.SUB;
}
else if(c1=='*'){
cUnit.type=CaculateType.MUL;
}
else if(c1=='/'){
cUnit.type=CaculateType.DIV;
}
if(_opStack.size()<=0){
_opStack.push(cUnit);
}
else{
//--假如栈顶有东西,那么就比较一下操作符的优先级,假如现在的优先级比栈顶高,那么入栈,否则,依次出栈---放到结果栈,直到栈空
//或栈顶优先级比找到的操作符低。
CaculateUnit _top1=_opStack.pop();
if(isHighLevel(cUnit, _top1)==1){
_opStack.push(_top1);
_opStack.push(cUnit);
}
else{
_ResultStack.push(_top1);
while(_opStack.size()>0){
CaculateUnit _topI=_opStack.pop();
if(isHighLevel(cUnit, _topI)>=0){
_ResultStack.push(_topI);
}
else{
_opStack.push(_topI);
_opStack.push(cUnit);
break;
}
}
if(_opStack.size()<=0){
_opStack.push(cUnit);
}
}
}
}
else{
//--假如是操作数。
}
}
if(preLoc<=res.length()-1){
String str_op=res.substring(preLoc,res.length());
CaculateUnit cOPUnit=new CaculateUnit();
cOPUnit.operationNumber=StringUtil.toFloat(str_op);
_ResultStack.push(cOPUnit);
}
//--假如操作栈还有符号,那么依次弹出来放进结果栈。
int opTotal=_opStack.size();
if(opTotal>0){
for(int i=1;i<=opTotal;i++){
CaculateUnit cTMP1=_opStack.pop();
_ResultStack.push(cTMP1);
}
}
return _ResultStack;
}
/**
* 获得包含小括号的四则运算的后缀表达式,这里指,只包含小括号,小数,整数,加减乘除的中缀表达式。
* 加上小括号与没有小括号的复杂程度是不同的,加上小括号后,我们任意一个小括号里面当成一个子表达式进行解析,
* 简而言之,需要用到递归对小括号这种树形结构进行处理。
* */
public int isHighLevel(CaculateUnit c1,CaculateUnit c2){
if(c1.type==CaculateType.Number||c2.type==CaculateType.Number){
return 0;
}
if(c1.type==CaculateType.DIV||c1.type==CaculateType.MUL){
if(c2.type==CaculateType.DIV||c2.type==CaculateType.MUL){
return 0;
}
return 1;
}
if(c2.type==CaculateType.DIV||c2.type==CaculateType.MUL){
return -1;
}
return 0;
}
public CaculateUnit getCaculateUnit(String str){
if(str==null||str.trim().length()<=0){
return null;
}
return null;
}
public float caculateHZS(Stack<CaculateUnit> stack){
float res=0;
ArrayList<CaculateUnit> _stackCopy=new ArrayList<CaculateUnit>();
for(int i=0;i<stack.size();i++){
_stackCopy.add(stack.get(i));
}
int opLoc=0;
while(_stackCopy.size()>1){
int total1=_stackCopy.size();
for(int ii=0;ii<total1;ii++){
CaculateUnit cUnit1=_stackCopy.get(ii);
if(cUnit1.type==CaculateType.DIV||cUnit1.type==CaculateType.SUB||cUnit1.type==CaculateType.PLUS||cUnit1.type==CaculateType.MUL){
CaculateUnit cUnit_res=new CaculateUnit();
if(cUnit1.type==CaculateType.SUB){
cUnit_res.operationNumber=_stackCopy.get(ii-2).operationNumber-_stackCopy.get(ii-1).operationNumber;
}
else if(cUnit1.type==CaculateType.PLUS){
cUnit_res.operationNumber=_stackCopy.get(ii-2).operationNumber+_stackCopy.get(ii-1).operationNumber;
}
else if(cUnit1.type==CaculateType.MUL){
cUnit_res.operationNumber=_stackCopy.get(ii-2).operationNumber*_stackCopy.get(ii-1).operationNumber;
}
else if(cUnit1.type==CaculateType.DIV){
cUnit_res.operationNumber=_stackCopy.get(ii-2).operationNumber/_stackCopy.get(ii-1).operationNumber;
}
_stackCopy.remove(ii);
_stackCopy.remove(ii-1);
_stackCopy.remove(ii-2);
_stackCopy.add(ii-2, cUnit_res);
break;
}
}
}
res=_stackCopy.get(0).operationNumber;
return res;
}
public void debug(Stack<CaculateUnit> stack){
for(int i=0;i<stack.size();i++){
CaculateUnit iUnit=stack.get(i);
switch (iUnit.type) {
case DIV:
System.out.print(" / ");
break;
case MUL:
System.out.print(" * ");
break;
case PLUS:
System.out.print(" + ");break;
case SUB:
System.out.print(" - ");break;
default:
System.out.print(" "+iUnit.operationNumber+" ");
break;
}
}
return;
}
}
下面要用到的几个类:
package Chacter4;
public class CaculateUnit {
public float operationNumber=0.0f;
public CaculateType type=CaculateType.Number;
}
package Chacter4;
public enum CaculateType {
Number,
DIV,
PLUS,
SUB,
MUL
}
一个工具类:
package Easis.Common;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class StringUtil {
public static void main(String[] args) {
String t="aaaaaaaaaa<table></table>aaa<table></table>";
String s="<TABLE";
// t="";
System.out.println("length="+t.length());
System.out.println(t.indexOf(s,0));
System.out.println(ignoreCaseIndexOf(t, s,0));
System.out.println(t.lastIndexOf(s));
System.out.println(ignoreCaseLastIndexOf(t, s));
}
/**
* 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始,不区分大小。
*
* @param subject 被查找字符串。
* @param search 要查找的子字符串。
* @return 指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
*/
public static int ignoreCaseIndexOf(String subject, String search) {
return ignoreCaseIndexOf(subject, search,-1);
}
/**
* 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始,不区分大小。
*
* @param subject 被查找字符串。
* @param search 要查找的子字符串。
* @param fromIndex 开始查找的索引位置。其值没有限制,如果它为负,则与它为 0 的效果同样:将查找整个字符串。
* 如果它大于此字符串的长度,则与它等于此字符串长度的效果相同:返回 -1。
* @return 指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
*/
public static int ignoreCaseIndexOf(String subject, String search,
int fromIndex) {
//当被查找字符串或查找子字符串为空时,抛出空指针异常。
if (subject == null || search == null) {
throw new NullPointerException("输入的参数为空");
}
fromIndex = fromIndex < 0 ? 0 : fromIndex;
if (search.equals("")) {
return fromIndex >= subject.length() ? subject.length() : fromIndex;
}
int index1 = fromIndex;
int index2 = 0;
char c1;
char c2;
loop1: while (true) {
if (index1 < subject.length()) {
c1 = subject.charAt(index1);
c2 = search.charAt(index2);
} else {
break loop1;
}
while (true) {
if (isEqual(c1, c2)) {
if (index1 < subject.length() - 1
&& index2 < search.length() - 1) {
c1 = subject.charAt(++index1);
c2 = search.charAt(++index2);
} else if (index2 == search.length() - 1) {
return fromIndex;
} else {
break loop1;
}
} else {
index2 = 0;
break;
}
}
//重新查找子字符串的位置
index1 = ++fromIndex;
}
return -1;
}
/**
* 返回指定子字符串在此字符串中最右边出现处的索引。
*
* @param subject 被查找字符串。
* @param search 要查找的子字符。
* @return 在此对象表示的字符序列中最后一次出现该字符的索引;如果在该点之前未出现该字符,则返回 -1
*/
public static int ignoreCaseLastIndexOf(String subject, String search){
if(subject==null){
throw new NullPointerException("输入的参数为空");
}
else{
return ignoreCaseLastIndexOf(subject,search,subject.length());
}
}
/**
* 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向查找。
* @param subject 被查找字符串 。
* @param search 要查找的子字符串。
* @param fromIndex 开始查找的索引。fromIndex 的值没有限制。如果它大于等于此字符串的长度,则与它小于此字符串长度减 1 的效果相同:将查找整个字符串。
* 如果它为负,则与它为 -1 的效果相同:返回 -1。
* @return 在此对象表示的字符序列(小于等于 fromIndex)中最后一次出现该字符的索引;
* 如果在该点之前未出现该字符,则返回 -1
*/
public static int ignoreCaseLastIndexOf(String subject, String search,
int fromIndex) {
//当被查找字符串或查找子字符串为空时,抛出空指针异常。
if (subject == null || search == null) {
throw new NullPointerException("输入的参数为空");
}
if (search.equals("")) {
return fromIndex >= subject.length() ? subject.length() : fromIndex;
}
fromIndex = fromIndex >= subject.length() ? subject.length() - 1 : fromIndex;
int index1 = fromIndex;
int index2 = 0;
char c1;
char c2;
loop1: while (true) {
if (index1 >= 0) {
c1 = subject.charAt(index1);
c2 = search.charAt(index2);
} else {
break loop1;
}
while (true) {
//判断两个字符是否相等
if (isEqual(c1, c2)) {
if (index1 < subject.length() - 1
&& index2 < search.length() - 1) {
c1 = subject.charAt(++index1);
c2 = search.charAt(++index2);
} else if (index2 == search.length() - 1) {
return fromIndex;
} else {
break loop1;
}
} else {
//在比较时,发现查找子字符串中某个字符不匹配,则重新开始查找子字符串
index2 = 0;
break;
}
}
//重新查找子字符串的位置
index1 = --fromIndex;
}
return -1;
}
public static boolean isEnglishCharacter(char c){
//ASCII中65-90号为26个大写英文字母,97-122号为26个小写英文字母。
if(c>=65&&c<=90){
return true;
}
if(c>=97&&c<=122){
return true;
}
return false;
}
public static boolean isNumberCharacter(char c1){
//--48~57为0-9字符、
if(c1 >=48&&c1<= 57 ){
//--是数字。
return true;
}
else{
return false;
}
}
/**
* 判断两个字符是否相等。
* @param c1 字符1
* @param c2 字符2
* @return 若是英文字母,不区分大小写,相等true,不等返回false;
* 若不是则区分,相等返回true,不等返回false。
*/
public static boolean isEqual(char c1,char c2){
// 字母小写 字母大写
if(((97<=c1 && c1<=122) || (65<=c1 && c1<=90))
&& ((97<=c2 && c2<=122) || (65<=c2 && c2<=90))
&& ((c1-c2==32) || (c2-c1==32))){
return true;
}
else if(c1==c2){
return true;
}
return false;
}
/**
* 根据数组拼接成为一串以sepstr为分隔符的字符串。
* @param list 需要拼接的数组
*@param sepStr 分隔符
* */
public static String spliceStringList(List<String> list,String sepStr){
if(list==null||list.size()<=0){
return "";
}
int thesize=list.size();
StringBuilder sb_res=new StringBuilder();
for (int i=0;i<thesize;i++){
sb_res.append(list.get(i)==null?"":list.get(i).toString());
if(i<thesize-1){
sb_res.append(sepStr);
}
}
return sb_res.toString();
}
/**
* 根据数组拼接成为一串以sepstr为分隔符的字符串。
* @param list 需要拼接的数组
*@param sepStr 分隔符
* */
public static String spliceIntegerList(List<Integer> list,String sepStr){
if(list==null||list.size()<=0){
return "";
}
int thesize=list.size();
StringBuilder sb_res=new StringBuilder();
for (int i=0;i<thesize;i++){
sb_res.append(list.get(i));
if(i<thesize-1){
sb_res.append(sepStr);
}
}
return sb_res.toString();
}
public static String Lpad(String originStr,char filledChar,int totalSize){
StringBuilder sb_res=new StringBuilder();
String c_str=originStr==null?"":originStr.trim();
int fillSize=totalSize-c_str.length();
//--检查里面的char有多少个中国,日本,韩国 字符,这些都是双字节,需要额外删除一个占位符
char[] char_arr=originStr.toCharArray();
for (char c1:char_arr){
if(isChineseCharacter(c1)||isJapaneseCharacter(c1)||isKoreanCharacter(c1)){
fillSize--;
}
}
sb_res.append(c_str);
for (int i=0;i<fillSize;i++){
sb_res.append(filledChar);
}
return sb_res.toString();
}
public static String Lpad_filledStr(String originStr,String filledStr,int totalSize){
StringBuilder sb_res=new StringBuilder();
String c_str=originStr==null?"":originStr.trim();
int fillSize=totalSize-c_str.length();
//--检查里面的char有多少个中国,日本,韩国 字符,这些都是双字节,需要额外删除一个占位符
char[] char_arr=originStr.toCharArray();
for (char c1:char_arr){
if(isChineseCharacter(c1)||isJapaneseCharacter(c1)||isKoreanCharacter(c1)){
fillSize--;
}
}
sb_res.append(c_str);
for (int i=0;i<fillSize;i++){
sb_res.append(filledStr);
}
return sb_res.toString();
}
//判断汉字第一批--普通中文字,\u4E00到\u9FA5,生冷中文字0x3400--0x4DB5
public static boolean isChineseCharacter(char c){
int c_code=(int)c;
//判断汉字第一批--普通中文字,\u4E00到\u9FA5
if(c_code>=(int)'\u4E00'&&c_code<=(int)'\u9FA5'){
return true;
}
//判断是否中文字---生冷中文字0x3400--0x4DB5
else if (c_code >= (int)'\u3400' && c_code <= (int)'\u4DB5')
{
return true;
}
return false;
}
//判断是否韩文--普通韩文0xAC00--0xD7A3
public static boolean isKoreanCharacter(char c){
//判断是否韩文--普通韩文0xAC00--0xD7A3
int theu_code=(int)c;
if (theu_code >= (int)'\uAC00' && theu_code <= '\uD7A3')
{
return true;
}
return false;
}
//判断是否日文3040-30FF, 31F0-31FF
public static boolean isJapaneseCharacter(char c){
//判断是否日文3040-30FF, 31F0-31FF
int theu_code=(int)c;
if (theu_code >= (int)'\u3040' && theu_code <= '\u30FF')
{
return true;
}
else if (theu_code >= (int)'\u31F0' && theu_code <= '\u31FF')
{
return true;
}
return false;
}
public static boolean isNullOrEmpty(String str){
if(str==null){
return true;
}
else if(str.trim().length()<=0){
return true;
}
else{
return false;
}
}
public static String FirstLetterUpperCase(String str){
if(str==null){
return null;
}
String str2=str.trim();
if (str2.length()<=1){
return str2.toUpperCase();
}
String str1= str2.replaceFirst(str2.substring(0, 1),str2.substring(0, 1).toUpperCase()) ;
return str1;
}
public static Boolean Str2Boolean(String str){
if(StringUtil.isNullOrEmpty(str)){
return false;
}
else{
String str1=str.toLowerCase().trim();
if(str1.equals("true")||str1.equals("1")){
return true;
}
}
return false;
}
public static int Str2Integer(String str){
if(isNullOrEmpty(str)){
return 0;
}
if(Validation.isInteger(str.trim())==false){
return 0;
}
else{
try{
return Integer.parseInt(str);
}
catch (Exception e){
return 0;
}
}
}
/**
* "yyyy-MM-dd HH:mm:ss"
* */
public static String FormatDateTime(Date theDate,String format){
Date _date=theDate==null?new Date():theDate;
SimpleDateFormat simpleDateFormat=new SimpleDateFormat(format);
return simpleDateFormat.format(_date);
}
public static Boolean toBoolean(String originstr){
if(originstr==null){
return false;
}
String str=originstr.toLowerCase().trim();
if(str.equals("true")||str.equals("1")){
return true;
}
return false;
}
public static int toInt(String originStr){
int i=0;
if(originStr==null){
return 0;
}
try{
String theOrignstr=originStr;
i= Integer.parseInt(theOrignstr);
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】转换成为整数!");
}
return i;
}
public static float toFloat(String originStr){
float i=0;
try {
i= Float.parseFloat(originStr);
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】转换成为Float浮点数!");
}
return i;
}
public static double toDouble(String originStr){
double i=0;
try {
i= Double.parseDouble(originStr);
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】转换成为Double浮点数!");
}
return i;
}
public static String toString(Object originStr){
if(originStr==null){
return "";
}
else{
return originStr.toString();
}
}
public static Short toShort(String originStr){
Short i=0;
try {
i= Short.parseShort(originStr);
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】转换成为Double浮点数!");
}
return i;
}
/**
* format格式 如:yyyy-MM-dd
* */
public static Date toDate(String originStr,String format){
Date mydate=new Date();
try{
SimpleDateFormat sdf=new SimpleDateFormat(format);//小写的mm表示的是分钟
String dstr=originStr;
Date date=sdf.parse(dstr);
return date;
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】按照格式【“"+format+"”】转换成为日期!");
}
return mydate;
}
public static Date toDate(String originStr){
Date mydate=new Date();
try{
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");//小写的mm表示的是分钟
String dstr=originStr;
Date date=sdf.parse(dstr);
return date;
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】按照格式【“"+"yyyy-MM-dd"+"”】转换成为日期!");
}
return mydate;
}
public static Long toLong(String originStr){
try{
return Long.parseLong(originStr);
}
catch (Exception e){
System.out.println("警告:StringUtil,错误原因:无法将【"+originStr+"】转换成为Long参数!");
return Long.parseLong("0");
}
}
/**
*获取某个字符串里面,一个字符出现的次数。
* */
public static int getCharCount(String originStr,char c){
if(StringUtil.isNullOrEmpty(originStr)){
return 0;
}
int total_1=0;
for(char c1:originStr.toCharArray()) {
if(c1==c){
total_1++;
}
}
return total_1;
}
}
下面看看测试结果:
该中缀表达式对应的后缀表达式为:
3.0 3.0 * 4.0 * 2.0 / 4.0 2.0 / + 1.0 / 3.0 * 1.0 2.0 * - 3.0 * 7.0 + 2.0 - 3.0 +
计算结果为:182.0