【Java数据结构与算法】 应用篇(1):栈实现四则表达式运算、栈实现带符号的四则表达式计算

10 篇文章 0 订阅
9 篇文章 0 订阅

大家好,我是皮皮猫吖!

每文一言:人生最低谷的时候那只是在缓冲,是达到最高点必须经过的地方。

本篇文章:

主要是关于java数据结构与算法的一些应用:栈实现四则表达式计算、栈实现带符号的四则表达式计算。

正文如下:

一、应用一:栈结构实现四则表达式计算

1)简单四则表达式计算的实现流程:

在这里插入图片描述

2)简单四则表达式的代码分析:
package com.data.structure.study4.stack;

/**
 * @author imppm
 * @create 2021-03-09-20:26
 */
public class Stack3CalculatorStack1 {
    public static void main(String[] args) {
        Stack3 stack3 = new Stack3();

        stack3.compute("7*2*2-5+1-5+3-4");//18
        stack3.compute("100-2-3*2");//104
    }
}

class Stack3{

    //栈数组:存储运算符
    private char[] operatorStack = new char[10];

    //栈数组:存储数据
    private int[] dataStack = new int[10];


    //设置加法的优先级
    private final int sumPriority = 0;

    //设置减法的优先级
    private final int subPriority = 0;

    //设置乘法的优先级
    private final int mulPriority = 1;

    //设置除法的优先级
    private final int divPriority = 1;

    //数据索引
    private int dataTop = -1;
    //运算符索引
    private int operatorTop = -1;

    //运算和
    private int dataSum = 0;


    //表达式的计算
    public void compute(String data){
        int continuous = 0;

        //循环字符串
        for (int i = 0; i < data.length(); i++){
            //当前字符串字符为数字
            if(data.charAt(i)>='0' && data.charAt(i)<='9'){
                //判断是否是多位数
                continuous++;

                //如果连续值大于1,表示连续多个字符是数字,对栈存储的数字进行更新
                if(continuous>1){
                    dataStack[dataTop] = dataStack[dataTop] * 10 + (data.charAt(i)-'0');
                }else {
                    //直接将数据字符压入到数据栈中
                    dataStack[++dataTop] = data.charAt(i) - '0';
                }

                //输入最后一个数据:进行计算
                if(i+1 == data.length()){
                    //指导运算符栈为空
                    while(!operatorStackIsEmpty()){
                        //拿出数据栈顶元素
                        int data1 = dataStack[dataTop--];
                        //数据栈顶元素的下一个元素
                        int data2 = dataStack[dataTop--];
                        //使用运算符进行计算
                        dataSum = operatorCompute(data2, data1, operatorStack[operatorTop--]);
                        //将计算之后的值,放入到数据栈中
                        dataStack[++dataTop] = dataSum;
                    }
                }
            }
            //当前字符为运算符
            else {

                //出现运算符,数字连续值就置为0
                continuous = 0;

                //如果运算符栈为空:直接压入栈中
                if(operatorStackIsEmpty()){
                    operatorStack[++operatorTop] = data.charAt(i);
                }
                //运算符栈不为空
                else{
                    //当前运算符的优先级大于栈顶运算符的优先级:运算符直接压入运算符栈中
                    if(!isStackOperatorPriorityBig(data.charAt(i))){
                        operatorStack[++operatorTop] = data.charAt(i);
                    }
                    //当前运算符的优先级小于等于栈顶运算符优先级:拿出栈顶运算符进行计算
                    else{
                        while (isStackOperatorPriorityBig(data.charAt(i))){
                            //获取栈顶运算符
                            char stackTopOperator = getStackTopOperator();
                            //获取栈顶数据1
                            int data1 = dataStack[dataTop--];
                            //获取栈顶数据2
                            int data2 = dataStack[dataTop--];
                            //数据1、数据2进行栈顶运算符操作
                            dataSum = operatorCompute(data2, data1, stackTopOperator);
                            //数据栈更新数据
                            dataStack[++dataTop] = dataSum;
                            //运算符栈顶元素-1
                            operatorTop--;
                            //判断运算符栈是否为空
                            if(operatorStackIsEmpty()){
                                break;
                            }
                        }
                        //把当前这个运算符压入到数据栈中
                        operatorStack[++operatorTop] = data.charAt(i);
                    }
                }
            }
        }
        System.out.println("计算结果为:"+dataSum);
    }


    //判断运算符栈是否为空
    private boolean operatorStackIsEmpty(){
        return operatorTop == -1;
    }

    //获取运算符栈栈顶元素
    private char getStackTopOperator(){
        return operatorStack[operatorTop];
    }

    //获取运算符的优先级
    private int getPriority(char operator){
        switch (operator){
            case '+':
                return sumPriority;
            case '-':
                return subPriority;
            case '*':
                return mulPriority;
            case '/':
                return divPriority;
            default:
                return -1;
        }
    }

    //使用对应的运算符进行计算
    private int operatorCompute(int a, int b, char operator){
        switch (operator){
            case '+':
                return a + b;
            case '-':
                return a - b;
            case '*':
                return a * b;
            case '/':
                return a / b;
            default:
                return -1;
        }
    }


    //判断运算符栈顶元素与当前运算符的优先级
    private boolean isStackOperatorPriorityBig(char operator){
        //获取栈顶的运算符数据
        char topOperatorData = getStackTopOperator();

        //获取到栈顶运算符的优先级
        int topDataPriority = getPriority(topOperatorData);

        //获取要加入栈中运算符的优先级
        int currentPriority = getPriority(operator);

        //如果栈顶的运算符的优先级大于当前运算符的优先级,计算栈顶数据
        if(topDataPriority >= currentPriority){
           return true;
        }else{
            //将运算符加入到运算符栈中
            return false;
        }
    }
}

二、应用二:栈结构实现带小括号的四则表达式计算:(1 + 2) - 3 * 4 + 2 * (1+2) = -3

1)带小括号的四则表达式的实现过程

在这里插入图片描述

2)带小括号的四则表达式的代码分析:
package com.data.structure.study4.stack;

/**
 * 含小括号的四则运算:
 *  如何处理小括号:
 *      设置左括号的优先级为最大值,设置右括号的优先级为最小级
 *          ① 如果左括号的优先级大于栈顶优先级,左括号入栈
 *          ② 如果栈顶元素为"(",当前运算符不为")",直接将这个运算符压入栈中
 *          ③ 如果栈顶元素为"(",当前运算符为")",直接将这"("运算符出栈,右括号运算符也不入栈
 * @author imppm
 * @create 2021-03-11-8:14
 */
public class Stack3CalculatorStack2 {
    public static void main(String[] args) {
        Stack4 stack4 = new Stack4();

        //stack4.compute("7*2*2-5+1-5*3-4");//18
        //stack4.compute("7*2*2-2*1-5*3-4");//7
        //stack4.compute("100-(2-3)*2");//104

        stack4.compute("(1+2)-3*4+2*(1+2)");//3-12+6=-3
    }
}

class Stack4 {
    //创建数据栈
    private int[] dataStack = new int[10];

    //创建运算符栈
    private char[] operatorStack = new char[10];

    //加法运算符的优先级
    private final int sumPriority = 0;

    //减法运算符的优先级
    private final int subPriority = 0;

    //乘法运算符的优先级
    private final int mulPriority = 1;

    //除法运算符的优先级
    private final int divPriority = 1;

    //左括号运算符的优先级
    private final int leftBracketsPriority = 2;

    //右括号运算符的优先级
    private final int rightBracketPriority = -1;

    //数据栈栈顶指针
    private int dataTop = -1;
    //运算符栈栈顶指针
    private int operatorTop = -1;

    //运算符标记位:出栈,入栈的标志
    private int operatorFlag = 0;

    //数据标志位:出栈、入栈的标志位
    private int dataFlag = 1;

    //获取运算符的优先级
    private int getOperatorPriority(char ch) {
        switch (ch) {
            case '+':
                return sumPriority;
            case '-':
                return subPriority;
            case '*':
                return mulPriority;
            case '/':
                return divPriority;
            case '(':
                return leftBracketsPriority;
            case ')':
                return rightBracketPriority;
            default:
                throw new RuntimeException("无法获取该字符的优先级!");
        }
    }

    //算式运算
    public void compute(String data) {
        //用来判断是否连续输入数字
        boolean flag = false;

//        遍历字符串
        for (int i = 0; i < data.length(); i++) {
            char ch = data.charAt(i);
            //是数字:直接压入数据栈中
            if (isDigit(ch)) {
                if(flag){
                    //获取到当前栈的第一个数据
                    int i1 = (int)pop(dataFlag);
                    //连续输入字符:拿到当前栈顶数据,数据*10+读取到的下一位
                    push(i1*10 + (ch - '0'));
                }else{
                    //没有连续输入数字,直接压入数据栈中
                    push((int) (ch - '0'));
                }
                flag = true;
            }

            //是字符
            else {
                flag = false;

                //栈中无运算符,将该运算符压入运算符栈中
                if (operatorTop == -1) {
                    push(ch);
                    continue;
                }

                //输出运算符栈
                while(true) {
                    if(operatorTop==-1){
                        break;
                    }
                    //栈中有运算符
                    //获取栈顶运算符
                    char operatorStackTopDat = getOperatorStackTopData();

                    //如果栈顶元素优先级小于当前运算符优先级,将当前运算符直接压入栈中
                    if (getOperatorPriority(ch) > getOperatorPriority(operatorStackTopDat)) {
                        //直接将运算符压入栈中
                        push(ch);
                        break;
                    }

                    //栈顶元素优先级大于等于当前运算符优先级,进行计算
                    else {
                        
                        //获取到运算符栈栈顶元素
                        char operator = (char) pop(operatorFlag);

                        //如果栈顶运算符为'('的时候,
                        //无法进行运算符操作,直接将"("和该运算符都压入栈中
                        if(operator=='(' && ch!=')'){
                            push('(');
                            push(ch);
                            break;
                        }
                        //如果运算符栈顶元素为'(',当前ch为')',直接跳出
                        else if(operator=='('){
                            break;
                        }

                        //上一个运算符不为'(',进行计算
                        //数据栈栈顶数据1
                        int num1 = (int) pop(dataFlag);
                        //数据栈栈顶数据2
                        int num2 = (int) pop(dataFlag);

                        //使用运算符计算的结果
                        int num = operatorCompute(num1, num2, operator);

                        //将计算的结果压入栈中
                        push(num);

                        //当前运算符栈为空,将当前运算符压入栈中
                        if(operatorTop==-1){
                            push(ch);
                            break;
                        }
                    }
                }
            }
        }

        //最后一步:遍历运算符栈
        //如果操作符栈为空
        while (operatorTop!=-1){
            //获取操作符栈数据
            char operator = (char)pop(operatorFlag);

            //获取数据栈栈顶数据1
            int num1 = (int)pop(dataFlag);
            //获取数据栈栈顶数据2
            int num2 = (int)pop(dataFlag);

            //通过运算符进行运算
            int num = operatorCompute(num1, num2, operator);

            //将运算结果压入到数据栈中
            push(num);
        }
        System.out.println(data+" = "+dataStack[dataTop]);
    }



    public boolean isDigit(char ch) {
        return ch >= '0' && ch <= '9';
    }

    //两个数据进行操作符运算
    private int operatorCompute(int a, int b, char ch) {
        switch (ch) {
            case '+':
                return a + b;
            case '-':
                return b - a;
            case '*':
                return a * b;
            case '/':
                return b / a;
            default:
                throw new RuntimeException("无法获取该字符的优先级!");
        }
    }

    //获取操作符栈顶元素
    public char getOperatorStackTopData() {
        return operatorStack[operatorTop];
    }

    //入栈
    public void push(Object data) {
        if (data instanceof Integer) {
            int i = (Integer) data;
            dataStack[++dataTop] = i;
        } else {
            char ch = (Character) data;
            operatorStack[++operatorTop] = ch;
        }
    }

    //出栈
    public Object pop(int choice) {
        //如果传入的是1,数据栈栈顶元素出栈
        if (choice == 1) {
            if (dataTop == -1) {
                throw new RuntimeException("数据栈空!无数据出栈!");
            }
            return dataStack[dataTop--];
        }

        //如果传入的是0,运算符栈栈顶元素出栈
        else {
            if (operatorTop == -1) {
                throw new RuntimeException("运算符栈空!无数据出栈!");
            }
            return operatorStack[operatorTop--];
        }
    }

}


希望本篇文章对大家有所帮助,后续会继续分享java数据结构与算法相关学习知识…

如果文章内容有错误的地方,请在留言处留下你的见解,方便大家共同学习。谢谢!

如有侵权或其他任何问题请联系:QQ1370922071,本文主要用于学习交流,转载请声明!

作者:皮皮猫吖


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值