java實現表達式求值(算符優先算法,可計算int,double,float 形數據)

1.首先要實現一個運算符關係表(根據運算符的優先權生成)

import java.util.ArrayList;

public class RuleTable {
	
	//此表可添加
	//操作符
	static public char[] op  = {
			'+',
			'-',
			'x',
			'/',
			'(',
			')',
			'#'
	};
	
	//優先關係模擬表
	//此表可添加
	private int[][] re = {
			{1,1,-1,-1,-1,1,1},
			{1,1,-1,-1,-1,1,1},
			{1,1,1,1,-1,1,1},
			{1,1,1,1,-1,1,1},
			{-1,-1,-1,-1,-1,0,2},
			{1,1,1,1,-2,1,1},
			{-1,-1,-1,-1,-1,2,0},
	};
	//申明一個運算優先規則列表
	private ArrayList<Rule> ruleList = new ArrayList<>();
	
	//獲取運算優先規則列表
	public ArrayList<Rule> getRuleList() {
		return this.ruleList;
	}
	//生成運算優先關係表
	public RuleTable() {
		
		for(int i = 0; i < op.length; i++) {
			for(int j = 0; j < op.length; j++) {
				Rule rule = new Rule();
				rule.ch1 = op[i];
				rule.ch2 = op[j];
				if(re[i][j] == 1) {
					rule.equ = '>';
				}else if(re[i][j] == -1) {
					rule.equ = '<';
				}else if(re[i][j] == 0) {
					rule.equ = '=';
				}else {
					rule.equ  = '@';
				}
				
				ruleList.add(rule);
			}
		}
	}
	//今設 第一個操作符爲a 第二個爲 b
	//當第一個爲 運算符第二個位分割符
	//則運算符小於分割符
	//如果第一個爲分隔符第二個爲運算符
	//則運算符大於分隔符
}
//優先規則關係表元素
class Rule {
	char ch1 = 0;
	char ch2 = 0;
	char equ = 0;
}
2.實現算法的核心類

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Stack;


public class CalculateStack {
	static private CalculateStack cl = new CalculateStack();
	//申明一個存放數字元素的棧
	private Stack<String> num = new Stack<>();
	//聲明一個存放操作符的棧
	private Stack<Character> opStack = new Stack<>();
	//申明一個優先權規則關係表
	private RuleTable ruleTable = new RuleTable();
	
	//運算簡單表達式 
	//測試通過
	//可添加運算規則
	private double getCalculateNumber(double num1,Character op,double num2) {
		
		double res = 0;
		switch(op.charValue()) {
		
			case '+':{
				res = num1 + num2;
			}break;
			
			case '-':{	
				res = num1 - num2;
			}break;
			case 'x':{
				
				res = num1 * num2;
			}break;
			case '/':{
				
				res = num1 / num2;
			}break;

		}
		return res;
	}
	
	//得到指定的倆個操作符的優先關係
	/**
	 * @return 當返回@時爲無效字符輸入
	 * */
	private char serchOp(char ch, char top) {
		
		//System.out.println("ch:"+ch+"   top:"+top);
		for(Rule rule:this.ruleTable.getRuleList()) {
			if(top == rule.ch1&&rule.ch2 == ch) {
				//System.out.println("從表中找到:關係爲top" + rule.equ +"ch");
				return rule.equ;
			}
		}
		return '@';
	}
	/**
	 * @author shilec
	 * 主運算算法
	 * @param ch1 :保存運算表達式的字符串數組
	 * @return Accuracy 得到運算的結果保留小數後的位數
	 * */
	public String Calculate(String strSource,int Accuracy) {
		boolean ret = true;
		
		Object[] ch1 = this.strToOpStr(strSource);
		//遍歷表達式數組,逐個讀入
		for(int i = 0; i < ch1.length; i++) {
			//判斷是否是操作符
			if(ch1[i].toString().isEmpty())
				break;
		if(!this.isOperator(ch1[i].toString())) {
			//不是則如數字字符棧
			this.num.push(ch1[i].toString());
			
		}else {
				//System.out.println(ch);
				//從優先關係表中查找當前字符和操作符棧棧頂元素的運算優先關係
				switch(this.serchOp(ch1[i].toString().charAt(0),this.opStack.lastElement())){
					//如果ch優先順序大於top 壓入操作符棧
					case '<':{
						
						this.opStack.push(new Character(ch1[i].toString().charAt(0)));
						//System.out.println(ch1[i].charAt(0)+"壓入操作符");
					}break;
					//如果ch優順序小於top 取出 倆個操作數以及彈出操作符進行運算
					case '>': {
						//彈出倆個數字元素
						double num2 = Double.valueOf(this.num.pop());
		
						double num1 = Double.valueOf(this.num.pop());
						
						char op = this.opStack.pop();
						//System.out.println(ch1[i].charAt(0)+"彈出操作符");
						this.num.push(new Double(this.getCalculateNumber(num1, op, num2)).toString());
						//但前元素不進行操作,返回重新進行比較
						//棧頂元素運算,退棧
						i--;
					}break;
					case '@': {
						System.out.println("不合法的表達式");
						ret = false;
					}break;
					
					case '=': {
						//去括號,#號
						this.opStack.pop();
						//System.out.println(ch1[i].charAt(0)+"彈出操作符");
					}break;
				}
			}
		}
		//格式化結果
		NumberFormat nb = NumberFormat.getNumberInstance();
		nb.setMinimumFractionDigits(Accuracy);
		double res = Double.valueOf(this.num.pop());
		
		return ret?nb.format(res):null;
	}
	
	/**
	 * 此函數用於在表達式進入運算之前檢查表達式的合法性
 * */
 private boolean CheckeStr(String strSource) {
		
		char[] chSource = strSource.toCharArray();
		//先檢查括號的數量
		for(int i = 1; i < chSource.length; i++) {
			if((chSource[i-1] == '('||chSource[i-1] == ')')&&!this.isOperater(chSource[i])) {
				return false;
			}else if((chSource[i] == '('||chSource[i] == ')')&&!this.isOperater(chSource[i-1])) {
				return false;
			}
		}
		return true;
	}
	
	//初始化倆個棧
	private CalculateStack() {
		//操作數棧初始化棧頂爲0
		this.num.push(new Integer(0).toString());
		//操作符棧初始化爲#(結尾符)
		this.opStack.push(new Character('#'));
	}
	
	//判斷字串是否爲操作符
	private boolean isOperator(String str) {
		
		if(str.toCharArray().length == 1) {
				for(char ch:RuleTable.op) {
					if(ch == str.toCharArray()[0])
						return true;
				}
		}else if(str.isEmpty()){
				return false;
		}else {
			return false;
		}
		return false;
	}
	
//此方法實現把操作符和操作數解析爲字符串數組
 private Object[] strToOpStr(String strSource) {
		int num = 0;
		boolean isOp = true; 
		String[] retStr = new String[100]; 
		
		char[] ch = strSource.toCharArray();
		for(char ch1:ch) {
			//起始爲數字
			if(this.isOperater(ch1)&&num == 0&&!isOp) {
				num++;
				retStr[num++] = new String(new Character(ch1).toString());
				isOp = true;
			}else if(this.isOperater(ch1)&&num == 0&&isOp) {
				//以操作符起始
				retStr[num++] = new String(new Character(ch1).toString());
				isOp = true;
			}else if(this.isOperater(ch1)&&num != 0){
				//不是起始位置並且是操作符
				if(!isOp)//如果前一個不是操作符 增加num
					num++;
				retStr[num++] = new String(new Character(ch1).toString());
				isOp = true;
			}else if(!this.isOperater(ch1)&&num != 0){
				//當前數字並且不是起始位置
				if(retStr[num] == null)
					retStr[num] = new String(new Character(ch1).toString());
				else {
					retStr[num] += ch1;
				}
				
				isOp = false;
			}else if(!this.isOperater(ch1)&&num == 0) {
				
				if(isOp) {
					//System.out.println("opchar:" + ch1+"op:"+isOp+"num:"+num);
					retStr[num] = new String(new Character(ch1).toString());
					//System.out.println("opchar:" + ch1+"op:"+isOp+"num:"+num+"rerStr:"+retStr[num]);
				}else {
					retStr[num] += ch1;
					//System.out.println("opchar:" + ch1+"op:"+isOp+"num:"+0+"rerStr:"+retStr[0]);
				}
				isOp = false;
			}	
		}
		ArrayList<String> list = new ArrayList<>();
		for(int i = 0; i < retStr.length; i++) {
			if(retStr[i] != null) {
				list.add(retStr[i]);
			}
		}
		list.add(list.size(),"#");
		return list.toArray();
	}
	//判斷一個字符是否爲操作符
	private boolean isOperater(char ch) {
		
		for(char ch1:RuleTable.op) {
			if(ch == ch1)
				return true;
		}
		return false;
	}
//demo
 public static void main(String[] args) {
		
		CalculateStack cl = CalculateStack.getCalculateInstance();
		System.out.println(cl.Calculate("(35-5)x2-1.11", 3));
		
	}
	//得到計算核心類的實例
	static public CalculateStack getCalculateInstance() {
		return  cl;
	}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章