zoukankan      html  css  js  c++  java
  • 带括号的四则混合运算的算符优先算法-----java实现

    1:主方法

    package com.baidu;


    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("(3x4)/1.11-3x45+12-12333", 1));

    }
    //得到计算核心类的实例
    static public CalculateStack getCalculateInstance() {
    return cl;
    }
    }

     2:算法

    package com.baidu;

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

    姓名:曹晓阳 联系方式:1076675163@qq.com
  • 相关阅读:
    Solidworks草图或者特征无法删除怎么办
    Solidworks如何为装配体绘制剖面视图
    Solidworks如何在装配图中保存单独的一个零件
    [Algorithm] Check if a binary tree is binary search tree or not
    [PureScript] Break up Expressions into Cases in PureScript using Simple Pattern Matching
    [Docker] Hooking a Volume to Node.js Source Code
    [PureScript] Basic Data Constructors in PureScript
    [Algorithm] Check for balanced parentheses using stack
    [PureScript] Introduce to PureScript Specify Function Arguments
    [Node.js] process.nextTick for converting sync to async
  • 原文地址:https://www.cnblogs.com/CAOXIAOYANG/p/5681835.html
Copyright © 2011-2022 走看看