表达式求值(中缀表达式)--java版本

  中缀表达式是通用的算术或逻辑公式表示方法,符合人常规计算的思维.表达式求值的实现方法是栈的一个典型应用.
  在计算机中,任何一个表达式都是由操作数,运算符和界限符组成,该篇中仅仅讨论操作数为整型,界限符为各种括号,运算符为加减乘除及其,取余和平方的运算.
根据四则运算的规则:

    (1)先括号内,后括号外
    (2)先平方,在乘除取余,后加减
    (3)同级运算从左到右

  举例:{5*3^2+[7+(5-2)]}*3,这个例子可以先不看,先看下面的思路,等回过头来在拿例子来做实验
  根据运算规则设置各个运算符的优先级:

              '+','-':  0
          '*','/','%':  1
                  '^':  2
             '[',']':  -1
             '(',')':  -3
             '{','}':  -2    

计算过程栈区变化表:

序号 操作数栈 运算符栈 注释
0 { 遇到左括号直接进栈
1 5 { 遇到操作数直接进栈
2 5 { * 当前指向优先级大入栈
3 5 3 { * 操作数
4 5 3 { * ^ 优先级大入栈
5 5 3 2 { * ^ /
6 5 9 { * 当前指向符号优先级小,做计算
6 45 { + 优先级小,计算/优先级大,入栈
7 45 { + [ 左括号入栈
8 45 7 { + [ /
9 45 7 { + [ + 优先级大入栈
10 45 7 { + [ + ( 左括号入栈
11 45 7 5 { + [ + ( /
12 45 7 5 { + [ + ( - 优先级大入栈
13 45 7 5 2 { + [ + ( - /
14 45 7 3 { + [ + 遇到右括号计算
15 45 10 { 遇到右括号计算
16 55 遇到右括号计算
17 55 * /
18 55 3 * /
19 165

最终的结果就是165.

解决思路:

index指表达式字符串当前遍历到哪个位置

  1. 如果为左括号,就直接进入符号栈中.该操作为了后面的遍历过程中遇到右括号,与之进行配对.
//            如果为左括号直接进栈
            if (isLeft(s.charAt(index))) {
                operS.push(s.charAt(index));
                index++;
            }
  1. 如果当前指向元素为数字,则要考虑这是否是一个多位数,所以需要不断向后看一位,直到指向到了一个符号或者指向到了该表达式最后一位,就停止.将该数压入操作数栈中.
//            如果该元素为数字
            String number = "";
//    该元素不是括号,不是运算符,则为数字,该篇中如此考虑.
            while (!isOper(s.charAt(index)) && !isLeft(s.charAt(index)) && !isRight(s.charAt(index))) {
                number += s.charAt(index);
// 为了防止该数字到了表达式的最后一位,所以需要判断一下.否则会进入死循环
                if (index == s.length() - 1) break;
                index++;
            }
            if (number != "") {
                numS.push(Integer.parseInt(number));
            }

  1. 如果当前指向为运算符,则要考虑以下几种情况:
      a. 当前指向运算符优先级<=符号栈栈顶符号的优先级:需要从操作数栈中弹出两个数字,符号栈弹出一个符号,进行运算,运算结果压入操作数栈中.
      b. 当前指向运算符优先级>符号栈栈顶优先级:直接压入栈中
      c:额外考虑1:如果当前指向指向了表达式最后一位,而这一位恰好是一个数字,而此时,符号栈并没有空,还需要进行一次计算,所以考虑到当指向最后一位时也可以进入该讨论情况中.进行一次计算后,符号栈空,退出.
      d:额外考虑2:因为输入的时候可能会不小心连续输入了两个运算符或者更多,所以index++后,还需要考虑这意味是否是一个运算符,如果是,说明表达式输入不正确.
//            如果元素为运算符
            int num1, num2, oper, res;
//             当算式进行到最后一位时,还要进行一次计算才结束.
            if (isOper(s.charAt(index)) || index == s.length() - 1) {
//                如果符号栈为空,元素直接入栈
                while (!operS.isEmpty() &&
                        operS.priority(s.charAt(index)) <= operS.priority(operS.peek()) || !isOper(s.charAt(index))&&!isLeft(s.charAt(index)) && !isRight(s.charAt(index))) {
                    if (operS.isEmpty()) break;
                    num1 = numS.pop();
                    num2 = numS.pop();
                    oper = operS.pop();
                    res = campute(num1, num2, oper);
                    numS.push(res);

                }

//       最后一位时为数字,防止他进入符号栈,所以要进行一次判断
                if (isOper(s.charAt(index))) {
                    operS.push(s.charAt(index));
                    index++;
                    if (isOper(s.charAt(index))) {
                        System.out.println("连续的计算符号,错误");
                        return 99999;
                    }
                }


            }
  1. 如果当前指向为右括号. 这个时候先要计算括号内的表达式,所以此时应该出栈运算.运算过程中,遇到左括号停止运算.如果遇到的左括号和当前右括号优先级相同,则说明括号匹配成功,左括号出栈,index++越过当前右括号,继续进行运算.
     额外考虑到括号可能短缺或者匹配错误,当为右括号时先进行判断符号栈是否是空的.
// 如果元素为右括号
            if (isRight(s.charAt(index)) && !operS.isEmpty()) {
                while (!isLeft(operS.peek())) {
                    num1 = numS.pop();
                    num2 = numS.pop();
                    oper = operS.pop();
                    res = campute(num1, num2, oper);
                    numS.push(res);
                }
                if (operS.priority(s.charAt(index)) == operS.priority(operS.peek())) {
                    operS.pop();  //弹出栈顶的左括号
                    index++; //下一位越过当前右括号
                } else {
                    System.out.println("括号匹配错误");
                    return 99999;
                }
            }
  1. true循环结束条件
//            当符号栈为空并且 算式已经进行到结尾时 计算结束
            if (operS.isEmpty() && index == s.length() - 1) break;

  1. 结果
// 数字栈中最后留下的那一个数字就是最终的结果
        return numS.pop();

完整程序,可以自己在修改的简单一些

public class CamputeStackDemo {
    public static void main(String[] args) {
        String s = "{5^2%3^2+[7+(5+2)]*3}*2";
        int i = doCamputee(s);
        System.out.println(i);
    }
    /**
     *  主体
     * @param s   算式
     * @return  最终的结果
     */
    public static int doCamputee(String s) {
        int index = 0; // 字符串的索引
//        建立两个栈
        CamputeStack numS = new CamputeStack(50); // 数字栈
        CamputeStack operS = new CamputeStack(50); //符号栈
        while (true) {
//            如果为左括号直接进栈
            if (isLeft(s.charAt(index))) {
                operS.push(s.charAt(index));
                index++;
            }
//            如果该元素为数字
            String number = "";
            while (!isOper(s.charAt(index)) && !isLeft(s.charAt(index)) && !isRight(s.charAt(index))) {
                number += s.charAt(index);
                if (index == s.length() - 1) break;
                index++;
            }
            if (number != "") {
                numS.push(Integer.parseInt(number));
            }
//            如果元素为计算符号
            int num1, num2, oper, res;
//             当算式进行到最后一位时,还要进行一次计算才结束.
            if (isOper(s.charAt(index)) || index == s.length() - 1) {
//                如果符号栈为空,元素直接入栈
                while (!operS.isEmpty() &&
                        operS.priority(s.charAt(index)) <= operS.priority(operS.peek()) || !isOper(s.charAt(index))) {
                    if (operS.isEmpty()) break;
                    num1 = numS.pop();
                    num2 = numS.pop();
                    oper = operS.pop();
                    res = campute(num1, num2, oper);
                    numS.push(res);
                }

//       最后一位时为数字,防止他进入符号栈,所以要进行一次判断
                if (isOper(s.charAt(index))) {
                    operS.push(s.charAt(index));
                    index++;
                    if (isOper(s.charAt(index))) {
                        System.out.println("连续的计算符号,错误");
                        return 99999;
                    }
                }
            }
// 如果元素为右括号
            if (isRight(s.charAt(index)) && !operS.isEmpty()) {
                while (!isLeft(operS.peek())) {
                    num1 = numS.pop();
                    num2 = numS.pop();
                    oper = operS.pop();
                    res = campute(num1, num2, oper);
                    numS.push(res);
                }
                if (operS.priority(s.charAt(index)) == operS.priority(operS.peek())) {
                    operS.pop();  //弹出栈顶的左括号
                    index++; //下一位越过当前右括号
                } else {
                    System.out.println("括号匹配错误");
                    return 99999;
                }
            }
//            当符号栈为空并且 算式已经进行到结尾时 计算结束
            if (operS.isEmpty() && index == s.length() - 1) break;

        }
// 数字栈中最后留下的那一个数字就是最终的结果
        return numS.pop();
    }


    //    判断元素是否为数字或者为符号
    public static boolean isOper(char v) {
        if (v == '+' || v == '-' || v == '*' || v == '/' || v=='%' || v=='^') return true;
        return false;
    }
    // 判断是否为左括号
    public static boolean isLeft(int v) {
       if(v== '(' || v=='[' || v=='{') return true;
       return false;
    }
    //    判断是否为右括号
    public static boolean isRight(int v) {
        if (v == ')' || v == ']' || v == '}') return true;
        return false;
    }

    //    计算两个数计算的结果
    public static int campute(int num1, int num2, int oper) {
        int var = 0;
        switch (oper) {
            case '+': {
                var = num1 + num2;
                break;
            }
            case '-': {
                var = num2 - num1;
                break;
            }
            case '*': {
                var = num2 * num1;
                break;
            }
            case '/': {
                var = num2 / num1;
                break;
            }
            case '%':{
                var = num2%num1;
                break;
            }
            case '^':{
                var = 1;
                for(int i = 1 ; i <= num1 ; i++){
                    var *=num2;
                }
                break;
            }
            default: {
                System.out.println("该符号不正确");
                break;
            }
        }
        return var;
    }
}

//  栈的建立
class CamputeStack {
    private int maxSize; // 栈的大小
    private int[] stack; // 栈
    private int top = -1; //定义栈顶


    //    初始化栈
    public CamputeStack(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[maxSize];
    }
    //    判断栈是否为空
    public boolean isEmpty() {
        return top == -1;
    }
    //    判断栈是否为满
    public boolean isFull() {
        return top == maxSize - 1;
    }
    //    入栈
    public void push(int v) {
        if (isFull()) {
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = v;
    }
    //    出栈
    public int pop() {
        if (isEmpty()) {
            System.out.println("栈空");
            throw new RuntimeException("栈空");
        }
        int v = stack[top];
        top--;
        return v;
    }

    //    查看栈顶元素
    public int peek() {
        if (isEmpty()) {
            System.out.println("栈空");
            throw new RuntimeException("栈空");
        }
        return stack[top];
    }

    //    返回元素的优先级
    public int priority(int oper) {
        int val = 100;
        switch (oper) {
            case '*':
            case '%':
            case '/': {
                val = 1;
                break;
            }
            case '^':{
                val = 2;
                break;
            }
            case '+':
            case '-': {
                val = 0;
                break;
            }
            case '[':
            case ']': {
                val = -1;
                break;
            }
            case '{':
            case '}': {
                val = -2;
                break;
            }
            case '(':
            case ')': {
                val = -3;
                break;
            }

        }
        return val;
    }


}

此篇到此就结束了,大家生活愉快-^^-!!!

你可能感兴趣的:(数据结构)