第五章:栈

5.5栈实现综合运算(中缀表达式)

前缀表达式
1、 又称波兰式,前缀表达式的运算符位于操作数之前,举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6
2、 前缀表达式的计算机求值
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素和次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果
在这里插入图片描述
中缀表达式:中缀表达式就是常见的运算表达式,如(3+4)×5-6【就是我们日常所使用的】。中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作,因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作 (一般转成后缀表达式)【中缀表达式转换成后缀表达式也是一个难点】

后缀表达式
1、 后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后。举例说明: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 –
在这里插入图片描述

2、 后缀表达式的计算机求值
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素和栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。 在这里插入图片描述
使用栈实现综合运算(中缀表达式)

package com.atguigu04.stack;

/**
 * @author peng
 * @date 2021/11/15 - 20:10
 *
 * 使用栈来实现加法运算,主要思路:
 * 1、创建两个栈,一个用来存放数字,一个用来存放运算符
 * 2、读取表达式,判断表达式的字符,如果是数字就进数字栈。如果是符号,且符号栈当前为空,则直接进符号栈;如果当前符号栈不为空,则判断当前符号与
 * 栈顶符号的优先级,如果当前符号的优先级大于栈顶符号,则直接进栈;如果当前符号优先级小于栈顶符号,则数字栈弹出两个元素用符号栈的栈顶元素进行运算,
 * 将运算后的结果进数字栈,再将当前符号进符号栈
 */
public class Calculator {
    public static void main(String[] args) {
        String expression = "7*2*2-5+1-5+3-4";
        //先创建两个栈,一个数栈,一个符号栈
        CalculatorArrayStack numberStack = new CalculatorArrayStack(10);//数栈,用于存放数字
        CalculatorArrayStack operStack = new CalculatorArrayStack(10);//符号栈,用于存放符号
        char ch;//用来存放表达式中的字符
        String keep = "";//用来存放读取的字符串的字符
        for (int i = 0; i < expression.length(); i++) {
            ch = expression.charAt(i);
            if (operStack.isOper(ch)) {//先判断该字符是否是符号
                //如果该字符是符号,判断符号栈是否为空
                if(!operStack.isEmpty()) {
                    //如果符号栈不为空,判断当前字符与栈顶符号的优先级
                    try {
                        if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                            //如果当前符号的优先级小于符号栈栈顶符号的优先级,数栈弹出两个数,符号栈栈顶符号出栈,进行运算
                            //使用数栈的方法进行运算
                            int sum = numberStack.cal(numberStack.pop(), numberStack.pop(), operStack.pop());
                            //再将运算结果压进数栈中
                            numberStack.push(sum);
                            //将当前的符号压进符号栈
                            operStack.push(ch);
                        }else {
                            //如果当前符号的优先级大于符号栈栈顶符号的优先级,则当前符号直接进栈
                            operStack.push(ch);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }else {
                    //如果当前符号栈为空,则直接进栈
                    operStack.push(ch);
                }
            } else {
                //如果是数字,则直接进数字栈
                //因为当前的ch是字符,想要将其转换成数字,根据ASCII表,数字字符减去48就可以转变为数字
                //numberStack.push(ch - 48);
                //不过在这里存在一个大问题,那就是如果要进栈的数字是72,则会出现问题,必须对代码进行优化
                keep += ch;//将每一次的读取结果保存下来
                //如果当前的字符已经是最后一个字符了也不需要再往下判断了,直接进栈即可
                if (i == expression.length() - 1) {
                    numberStack.push(Integer.parseInt(keep));
                    break;
                }
                if (operStack.isOper(expression.charAt(i + 1))) {
                    //如果下一个字符是运算符,说明数字已经遍历完,可以直接进栈
                    numberStack.push(Integer.parseInt(keep));
                    keep = "";
                }
            }
        }
        //当全部数字和符号进栈之后,就将数栈中的数和符号栈中的符号取出来进行运算
        //最终留在数栈中的数字就是运算结果
        int sum = 0;//用来存在运算的结果
        while (true) {
            if (operStack.isEmpty()) {
                break;
            }
            try {
                sum = numberStack.cal(numberStack.pop(), numberStack.pop(), operStack.pop());
                numberStack.push(sum);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            System.out.println("该表达式的结果是:" + numberStack.pop());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * 定义栈
 */
class CalculatorArrayStack {
    private int maxSize;//栈的最大高度
    private int[] stack;//使用数组来模拟栈
    private int top = -1;//栈指针

    public CalculatorArrayStack(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }

    /**
     * 判断栈满
     */
    public boolean isFull() {
        return top == maxSize - 1;
    }

    /**
     * 判断栈空
     */
    public boolean isEmpty() {
        return top == -1;
    }

    /**
     * 入栈的操作
     */
    public void push(int value) {
        if (isFull()){
            System.out.println("栈已经满了!");
            return;
        }
        top++;
        stack[top] = value;
    }

    /**
     * 出栈的操作
     */
    public int pop() throws Exception {
        //首先判断栈是否为空
        if (isEmpty()) {
            //如果栈为空,则抛出异常
            throw new Exception("栈为空不能输出数据!");
        }
        //如果栈不为空
        int value = stack[top];
        top--;
        return value;
    }

    /**
     * 显示栈的情况,遍历时,需要从栈顶开始显示数据
     */
    public void list() {
        //首先判断栈是否为空
        if (isEmpty()) {
            System.out.println("当前栈为空!");
            return;
        }
        //如果栈不为空,那么就开始遍历栈
        for (int i = top; i > 0; i--) {
            System.out.println(stack[i]);
        }
    }

    /**
     * 定义运算符的优先级
     * 返回的数字越大,优先级越高
     */
    public int priority(int oper) {
        /*
        因为字符在底层是以数字进行存储的,所以可以直接使用数字来进行验证字符
         */
        if (oper == '*' || oper == '/') {
            return 1;
        }else if (oper == '+' || oper == '-') {
            return 0;
        }else {
            return -1;
        }
    }

    /**
     * 判断是不是运算符
     */
    public boolean isOper(char val) {
        return val == '+' || val == '-' || val == '*' || val == '/';
    }

    /**
     * 计算方法
     */
    public int cal(int num1, int num2, int oper) {
        int sum = 0;//用于保存运算的和
        switch (oper) {
            case '+':
              sum = num2 + num1;//在这里尤其要注意出栈的顺序
                break;
            case '-':
               sum = num2 - num1;
                break;
            case '*':
               sum = num2 * num1;
                break;
            case '/':
              sum = num2 / num1;
                break;
            default:
                break;
        }
        return sum;
    }

    /**
     * 返回当前的栈顶元素,但并不出栈
     */
    public int peek() throws Exception {
        //首先判断栈是否为空!
        if (isEmpty()) {
            throw new Exception("当前栈为空!");
        }
        int value = stack[top];
        return value;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值