栈的一个应用—关于中缀和后缀表达式求值

栈的一个应用—关于中缀和后缀表达式求值

  1. 中缀表达式直接转化为后缀表达式求值:
import java.util.Stack;
public class Suffix {
 static Stack<Character> op = new Stack<>();
    /*将中缀表达式转化为后缀表达式*/
    public static String tosuffix(String str) {
     char[]  str1=str.toCharArray();
     int len=str1.length;
        String res="";
        for(int i=0;i<len;i++) {
         char ch=str1[i];
         if(ch==' ') {continue;}
         if(ch>='0'&&ch<='9') {
          res=res+ch;
          continue;
         }
         if(ch=='('){
          op.push(ch);
         }
         if(ch=='+'||ch=='-') {
          while(!op.isEmpty()&&op.peek()!='(') {
           res+=op.pop();}
          op.push(ch);
             continue;
         }
         if(ch=='*'||ch=='/') {
          while(!op.isEmpty()&&(op.peek()=='*'||op.peek()=='/')) {res=res+op.pop();}
          op.push(ch);
          continue;
         }
         if(ch==')') {
          while(!op.isEmpty()&&op.peek()!='(') {
           res+=op.pop();
          }
          op.pop();
          continue;
         }
        }
        while(!op.empty()) {res+=op.pop();}
        return res;
    }
    //求值
    public static Float getValue(String str) {
     Stack<Float> v = new Stack<>();        
     char[] arr = str.toCharArray();        
     int len = arr.length;        
     for(int i = 0; i < len; i++){            
      Character ch = arr[i];             // if is operand, push to the stack            
      if(ch >= '0' && ch <= '9') 
       v.push(Float.valueOf(ch - '0'));             
      // if is operator, calculate the result            
      // with top 2 operands in the stack,            
      // push the result into the stack            
      else v.push(caculate(ch, v.pop(), v.pop()));        }        
     return v.pop();
     }
    public static Float caculate(char op,Float num1,Float num2) {
     switch(op) {
     case'+':
      return num1+num2;
     case'-':
      return num2-num1;
     case'/':
      return num2/num1;
     case'*':
      return num2*num1;
     default:return Float.valueOf(0);
     }
    } 
    public static void main(String[] args) {
     String str="5+4*3";
     System.out.println(getValue(tosuffix(str)));
     
    }
}
  1. 注:数字只能选择0-9之间的数字,而不能选择其他数字。
    要想更进一步输入双位数,则可以将数组的下一位也在同一步中进行判断,然后删除下一个数组的对应 元素,使得单一位存储双数个,而数组也将改为string类型。
    实现(先转化为数组,然后,在):
private static String[] strToExpressionArr(String str) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) < '0' || str.charAt(i) > '9') {
                str = str.substring(0, i) +" " + str.charAt(i) + " " +str.substring(i + 1, str.length());
                i += 2;
            }
        }
        Scanner sc = new Scanner(str);
        while (sc.hasNext())
            list.add(sc.next());
        return list.toArray(new String[list.size()]);
    }
  1. 利用双栈实现不转化就求值(其实相当于上面的两个栈,只不过是把中缀表达式转化为后缀表达式的过程变为分别将op与数据分别存入不同的栈中,然后挨个操作,符号边进栈边计算)
    重点是多了优先级的判断(*/±)。
 package;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Stack;
//不借助中缀表达式转化为后缀表达式的方法:将op与num分别存入两个不同的栈
public class caculator {
 public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入一个算术表达式:");
        String str = input.nextLine();
        compute(str);
    }
     //用字符串做参数重载的计算函数,调用下面用字符串数组做方法参数的函数
  public static void compute(String expression) {
        String[] arr = strToExpressionArr(expression);
        if (isLegalExpression(arr))
            System.out.println(compute(strToExpressionArr(expression)));
        else
            System.out.println("请输入合法表达式");
    }
    private static String[] strToExpressionArr(String str) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) < '0' || str.charAt(i) > '9') {
                str = str.substring(0, i) +" " + str.charAt(i) + " " +str.substring(i + 1, str.length());
                i += 2;
            }
        }
        Scanner sc = new Scanner(str);
        while (sc.hasNext())
            list.add(sc.next());
        return list.toArray(new String[list.size()]);
    }
    //计算算术表达式
    private static int compute(String[] expression) {
        Stack<Integer> numStack = new Stack<>();
        Stack<Character> opStack = new Stack<>();
        for (int i = 0; i < expression.length; i++) {
            String ele = expression[i];
            //如果是数字,进入数字栈
            if (isNumber(ele)) {
                numStack.push(new Integer(ele));
            }
            //以下是符号
            //遇到加减号,把栈顶的符号都处理完,直到遇到(左括号和栈空情况,最后把提取到的符号压入栈
            else if (ele.charAt(0) == '+' || ele.charAt(0) == '-') {
                while (!opStack.isEmpty() && opStack.peek() != '(') {
                    int b = numStack.pop();
                    int a = numStack.pop();
                    numStack.push(getAnswer(a, opStack.pop(), b));
                }
                if (!opStack.isEmpty() && opStack.peek() == '(')
                    opStack.pop();
                opStack.push(ele.charAt(0));
            }
            //遇到乘除号,把前面的乘除号处理完,最后把提取到的符号压入栈
            else if (ele.charAt(0) == '*' || ele.charAt(0) == '/') {
             //注意下一步中关于优先级的判断
                while (!opStack.isEmpty() && opStack.peek() != '(' &&
                        opStack.peek() != '+' && opStack.peek() != '-') {
                    int b = numStack.pop();
                    int a = numStack.pop();
                    numStack.push(getAnswer(a, opStack.pop(), b));
                }
                if (!opStack.isEmpty() && opStack.peek() == '(')
                    opStack.pop();
                opStack.push(ele.charAt(0));
            }
            //遇到左括号,只进栈
            else if (ele.charAt(0) == '(') {
                opStack.push(ele.charAt(0));
            }
            //遇到右括号,只处理栈顶全部符号
            else if (ele.charAt(0) == ')') {
                while (!opStack.isEmpty() && opStack.peek() != '(') {
                    int b = numStack.pop();
                    int a = numStack.pop();
                    numStack.push(getAnswer(a, opStack.pop(), b)); }
                if (!opStack.isEmpty() && opStack.peek() == '(')
                    opStack.pop();
            }
        }
        //最后没有以右括号结尾的表达式还得另外把剩下的符号处理完
        if (!opStack.isEmpty()) {
            int b = numStack.pop();
            int a = numStack.pop();
            numStack.push(getAnswer(a, opStack.pop(), b));
        }
        return numStack.peek();
    }
    //判断是否数字
    private static boolean isNumber(String s) {
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) < '0' || s.charAt(i) > '9')
                return false;
        }
        return true;
    }
    //四则运算
    private static int getAnswer(int a, char operator, int b) {
        switch (operator) {
            case '+': return a + b;
            case '-': return a - b;
            case '*': return a * b;
            case '/': return a / b;
        }
        return 0;
    }
    //判断表达式是否合法(加减乘除号左右必然有左端与右端、括号要一一对应(与做运算时候的判断方法相同))
    static boolean isLegalExpression(String[] arr) {
        //表达式的开头和结尾不能出现加减乘除符号
        char hc = arr[0].charAt(0);
        char tc = arr[arr.length - 1].charAt(0);
        if (hc == '+' || hc == '-' || hc == '*' || hc == '/' ||
                tc == '+' || tc == '-' || tc == '*' || tc == '/')
            return false;
        //括号要一一对应,而且开头不能是右括号,结尾不能是左括号
        Stack<Character> stk = new Stack();
        for (String s : arr) {
            if (s.charAt(0) == '(')
                stk.push(s.charAt(0));
            else if (s.charAt(0) == ')') {
                if (stk.isEmpty())
                    return false;
                stk.pop();
            }
        }
        if (!stk.isEmpty())
            return false;
        //不能出现非法字符,就是除了加减乘除和括号和数字外,不能出现其他字符
        String ts = "";
        for (String s : arr) {
            ts += s;
        }
        for (char c : ts.toCharArray()) {
            if (c != '+' && c != '-' && c != '*' && c != '/' && c != '(' && c != ')'&&!(c >= '0' && c <= '9'))
                return false;
        }
        //看每个数字两边是否缺少符号操作和每个符号两边是否缺少数字
        for (int i = 0; i < arr.length; i++) {
            char c = arr[i].charAt(0);
        //数字
            if (isNumber(arr[i])) {
                boolean hasLeft = true;
                boolean hasRight = true;
            if (i == 0)
                    hasLeft = false;
            if (i == arr.length - 1)
                    hasRight = false;
            //看左边是否有符号
                if (i > 0) {
                    char cha = arr[i - 1].charAt(0);
                    if (cha != '+' && cha != '-' && cha != '*' && cha != '/')
                        hasLeft = false;
                }
                //看右边有没有符号
                if (i < arr.length - 1) {
                    char cha = arr[i + 1].charAt(0);
                    if (cha != '+' && cha != '-' && cha != '*' && cha != '/')
                        hasRight = false;
                }
                //都没有就非法
                if (!hasLeft && !hasRight)
                    return false;
            }
            //运算符
            else if ( c == '+' || c == '-' || c == '*' || c == '/') {
                boolean hasLeft = true;
                boolean hasRight = true;
                if (i == 0)
                    hasLeft = false;
                if (i == arr.length - 1)
                    hasRight = false;
                //看左边是否有数字
                if (i > 0) {
                    if (!isNumber(arr[i - 1]))
                        hasLeft = false;
                }
                //看右边有没有数字
                if (i < arr.length - 1) {
                    if (!isNumber(arr[i + 1]))
                        hasRight = false;
                }
                //都没有就非法
                if (!hasLeft && !hasRight)
                    return false;
            }
        }
        return true;
    }
}

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值