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;
}
}