目录:


  • 环境及配置
  • 原理及步骤
  • 代码
  • 运行结果



1. 环境及配置:

  • 语言:Java
  • IDE:eclipse
  • 所用数据结构:Stack(栈)

2.原理及步骤:

中缀表达式就是我们日常生活中使用的习惯性的表达式,例如:1 + 2 * 3,这里我们实现从键盘接受一段中缀表达式,并对其进行求值,输出结果。

具体步骤如下:

  1. 首先从键盘接受一段中缀表达式。使用标准键盘输入System.in构造输入流,然后使用nextLine()接收一行字符串。
  2. 为了便于提取有效字符,这里构造了一个方法,返回一个字符串数组
    输入的中缀表达式有可能不符合规范,不便于提取存储每个有效字符,这里需要我们自己构造一个方法来将其格式化,便于提取单个有效字符。
  3. 使用2个栈来实现,一个存储操作数,一个存储操作符
  4. 遍历有效字符数组,按照下面的原则:
    1.左括号'('入栈
    2.数字'0'~'9'入栈
    3.遇到运算符号'+'、'-'、'*'、'/'时,将栈内优先级大于等于该运算符的符号出栈参与运算,结果入栈
    4.如果遇到有括号')',则对栈内所有的数字进行运算
  5. 这里计算也构造一个方法方便操作
  6. 最后,循环对操作数栈进行运算,直到操作符栈为空

3.代码:

Test.java

import java.util.Scanner;

// 中缀算术表达式求值
public class ExpressionEvaluation {

    public static void main(String[] args) throws Exception {
        Scanner input = new Scanner(System.in);
        LinkedStack<Integer> value = new LinkedStack<>();
        LinkedStack<Character> operation = new LinkedStack<>();

        System.out.print("请输入一个中缀表达式:");
        String[] expression = formatInput(input.nextLine());// 从键盘输入一个中缀表达式,然后格式化后存储为一个字符串数组

        // 首先,遍历expression数组,同时以下列原则进行操作,然后,对栈内的剩余数字进行运算,直到操作符栈为空
        for (String s : expression) {
            if (s.length() == 0)// 因为格式化的时候是在非数字符号前后加空格,所以会存在分割出来是空的情况
                continue;
            else if (s.charAt(0) == '+' || s.charAt(0) == '-' || s.charAt(0) == '*' || s.charAt(0) == '/') {// 遇到运算符,将栈内优先级大于等于自己的符号拿出来参与计算
                while (!operation.isEmpty() && priorityIsBiggerOrTheSame(operation.peek() + "", s)) {// 循环直到栈空或者遇到优先级较小的符号
                    compute(value, operation);
                }
                operation.push(s.charAt(0));// 当前符号入栈
            }
            else if (s.charAt(0) == '(')// 右括号入栈
                operation.push('(');
            else if (s.charAt(0) == ')') {// 遇到左括号,将栈内符号全部出栈参与运算
                while (operation.peek() != '(')// 循环直到遇到左括号
                    compute(value, operation);
                operation.pop();// 左括号出栈
            }
            else
                value.push(Integer.parseInt(s));// 数字入栈
        }
        while (!operation.isEmpty())// 最后将所有的符号出栈参与运算
            compute(value, operation);
        System.out.println("计算结果是:" + value.pop());
    }

    // 提取出操作数栈的前2个数,操作符栈的栈顶操作符,运算
    public static void compute(LinkedStack<Integer> value, LinkedStack<Character> operation) {
        int v1 = value.pop();
        int v2 = value.pop();
        char op = operation.pop();
        switch (op) {
            case '+':
                value.push(v2 + v1);
                break;
            case '-':
                value.push(v2 - v1);
                break;
            case '*':
                value.push(v2 * v1);
                break;
            case '/':
                value.push(v2 / v1);
                break;
        }
    }

    // 格式化中缀表达式输入,即在符号前后添加空格,便于后面的分隔操作
    public static String[] formatInput(String s) {
        String temp = "";
        /*
         * 提取出表达式中有效的字符(非空格),然后在字符后面统一添上一个空格,方便后面使用静态方法String.split()来 
         * 例如:1 *(2+ 3) /4     ----->     1 * ( 2 + 3 ) / 4 
         * 你也可以直接使用List类来存储提取的有效字符 总之最后的目的就是返回一个数组,其中存储的是有效字符
         */
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '+' || c == '-' || c == '*' || c == '/')
                temp += " " + c + " ";
            else
                temp += c;// 数字不用加空格
        }
        return temp.split(" ");// 分割
    }

    // 优先级判断,a是否大于b
    public static boolean priorityIsBiggerOrTheSame(String a, String b) {
        String s = "+- */";
        return (s.indexOf(a) - s.indexOf(b)) >= 2;
    }
}

ArrayStack.java

package stack;

import java.util.Iterator;
import java.util.Scanner;

/**
 * 使用数组实现的mini版的栈,只保留需要的方法
 * @author Super233
 * @param <E>泛型参数
 */
public class ArrayStack<E> implements Iterable<E> {
    private final int MAX_SIZE = 16;// 初始大小定为16

    private E[] data = null;// 数据域
    private int size = 0;// 栈中元素个数

    // 默认无参构造方法
    public ArrayStack() {
        data = (E[]) new Object[MAX_SIZE];
    }

    // 含参构造方法,实现栈的初始大小自定义
    public ArrayStack(int cap) {
        data = (E[]) new Object[cap];
    }

    // 入栈
    public void push(E e) {
        ensureCapcity();
        data[size++] = e;
    }

    // 出栈
    public E pop() {
        E top = data[size - 1];
        data[size - 1] = null;
        size--;
        return top;
    }

    // 获得栈顶元素
    public E peek() throws Exception {
        if (isEmpty())
            throw new Exception("The stack is Empty!");
        else
            return data[size - 1];
    }

    // 实现栈的大小不够时自动增加
    public void ensureCapcity() {
        if (size == data.length) {
            E[] temp = (E[]) new Object[data.length * 2];
            for (int i = 0; i < data.length; i++)
                temp[i] = data[i];
            data = temp;
        }
    }

    // 判空
    public boolean isEmpty() {
        return size == 0;
    }

    // 重写的toString()方法
    @Override
    public String toString() {
        String result = "data: ";
        for (int i = 0; i < size; i++)
            result += data[i] + " ";
        return result;
    }

    // 继承接口Iterable后需要重写的方法,返回一个迭代器
    @Override
    public Iterator<E> iterator() {
        return new ReverseIterator();
    }

    // 内部类迭代器,从栈顶到栈底访问数据
    private class ReverseIterator implements Iterator<E> {
        private int current = size - 1;// current表示当前下标,倒序遍历,所以current初始化为size-1

        @Override
        public boolean hasNext() {
            return current >= 0;// 倒序遍历,为了实现foreach,这里应该是>=0
        }

        @Override
        public E next() {
            return data[current--];
        }
    }
}

4.运行结果:

javacc算术表达式 java算术表达式求值_javacc算术表达式

PS:第一次写博客,献上米老鼠镇楼,寒假快乐

_-~~~-_       _-~~~-_
      /~       ~\    :    ,  \
     '           ~   ,   |:  :
    {      /~~\  :--~""""\.:  :
     \    (... :   /^\  /^\\ ;
      ~\_____     |   | | |:~
            /     |__O|_|O|;
           (     /       O \
            \   ( `\_______/)       ~~~❤
             `\  \         /
               )  ~-------~'\
              /              \
             :           ❤  ||
             |  |            ||
             |  |.======[]==+'|
            (~~~~)       |   |~)
            /    \       |   | \
~\          \___/)______/^\__|_/
  `\\      //    |  |      | |
    `\\__//'     |  |      | |
       ~~       (~~~~)    (~~~)
               /     =\..'    =_
              |__________)________)