Java栈思想应用——四则运算|附括号匹配

在这里插入图片描述

四则运算:
1、遍历四则运算式,遇到数字存入栈中
2、遇到符号,栈为空则入栈;否则需要比较是否计算
给每个符号±*/设置优先级;
栈顶优先级>=当前优先级,则符号出栈,出两个操作数,进行计算,结果入栈,当前符号入栈;
3、直至遍历完整个字符串,不为空则继续出栈计算结果压栈,直至符号栈为空;
4、实现栈的思想:先进后出:
数组:尾巴作为栈顶,方便进入出去;
链表:头结点为栈顶,方便插入删除

代码如下:
思路来源:该文章

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.youkuaiyun.com/qq_44366571/article/details/114825726

public class SiZeYunSuan {
//    1\遍历算术表达式
//    2、遇到数字入栈;
//    遇到符号:符号栈顶拿出作比较,
//    顶的优先级>=当前符号优先级就取数字栈顶两个数,计算结果压栈,当前大于栈顶的优先级,则压栈
    //两个栈,静态变量属于类而不是实例,因此可以在类的任何地方直接访问,不需要创建对象。
//    静态变量在所有实例之间共享,当一个实例修改了静态变量的值,其他实例也会受到影响。
    public static void main(String[] args)
    {
        Operation op=new Operation();
        op.operation_s("3*9+9+8*1");//预期=44
        //* + +

    }

}
class Operation{
    //存储运算符和操作数的两个数组
    private char[] operatorstack=new char[10];
    private int[] datastack=new int[10];
    //优先级
    private final int sump=0;//+
    private final int subp=0;//-
    private final int mulp=1;//*
    private final int divp=1;// /
//    数组索引
    private int operatortop=-1;
    private int datatop=-1;
    private static int datasum=0;//运算结果
    //判断运算符栈为空
    private boolean operatorstackisEmpty()
    {
        return operatortop==-1;
    }
    //获取优先级
    private int getpriority(char operator)
    {
        switch (operator)
        {
            case '+':
                return sump;
            case'-':
                return subp;
            case'*':
                return mulp;
            case '/':
                return divp;
            default:
                return -1;
        }

    }
    //计算
    //a是顶元素,b是顶元素的下一个,在遍历四则运算式的时候,前一个操作数先入栈
    private int operator(int a,int b,char operator_n)
    {
        System.out.println(a+" "+b+" "+operator_n);
        switch (operator_n){
            case '+':
                return a+b;
            case'-':
                return b-a;
            case'*':
                return b*a;
            case '/':
                return b/a;
            default:
                return -1;
        }

    }
    //判断栈顶元素和当前元素的优先级
    private boolean isoperationprioritybig(char operator)
    {
        char topoperatordata=operatorstack[operatortop];//获取栈顶元素
        int topdatapriority=getpriority(topoperatordata);
        int currentpriority=getpriority(operator);
        //当前<=栈顶优先级,就计算压栈
        if(topdatapriority>=currentpriority)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    //遍历s
    public void operation_s(String s)
    {
        int contins = 0;//多位数
        for (int i = 0; i < s.length(); i++)
        {
            if (s.charAt(i) >= '0' && s.charAt(i) <= '9')
            {
                contins++;
                if (contins > 1) {
                    //更新data数组元素
                    datastack[datatop] = datastack[datatop] * 10 + (s.charAt(i));
                } else {
                    //更新datatop
                    datastack[++datatop] = s.charAt(i) - '0';//压入的是数字字符
                }

                if(i+1==s.length())//当前为最后一个元素:数字
                {
                    //存放操作符的数组operatorstack不为空
                    while(!operatorstackisEmpty())//说明栈顶符号的运算优先级大,因为比较的时候出现了top<current则入栈
                    {
                        //数据栈顶;:取出两个操作数
                        int data1=datastack[datatop--];//相当于stack.pop()
                        int data2=datastack[datatop--];
                        //计算,操作数和操作符
                        datasum=operator(data1,data2,operatorstack[operatortop--]);
                        datastack[++datatop]=datasum;//计算结果压栈
                        System.out.println("计算结果为"+datasum);
                    }
                }
            }
            //为运算符
            else{
                contins=0;//数字位数=0
                //为空则压入栈
                if(operatorstackisEmpty())
                {
                    operatorstack[++operatortop]=s.charAt(i);
                }
                else
                {
                    //比较优先级
//                    !false
                    if(!isoperationprioritybig(s.charAt(i)))//top《current===》压栈
                    {
                        operatorstack[++operatortop]=s.charAt(i);//压入
                    }
                    else
                    {
                        while(isoperationprioritybig(s.charAt(i)))//top>=current则计算
                        {
                            char stacktoperator_temp=operatorstack[operatortop--];//栈顶元素
                            int data1=datastack[datatop--];//相当于stack.pop()
                            int data2=datastack[datatop--];
                            datasum=operator(data1,data2,stacktoperator_temp);
                            datastack[++datatop]=datasum;//结果压栈
                            if(operatorstackisEmpty())
                                break;//空了就跳出

                        }
                        //计算完栈内>=自己优先级的运算,再把自己(current)存入
                        operatorstack[++operatortop]=s.charAt(i);
                    }
                }
                System.out.println("计算结果为"+datasum);
            }
        }
        System.out.print("最终结果为"+datastack[0]);
    }
}

关于括号匹配:

public class KuoHaoStack {
    public static boolean  isok(String s)//O(n)
    {
        MyStack<Character> brackets=new ArrayStack<Character>(20);
        char[] c =s.toCharArray();
        for(char elem:c)
        {
            switch(elem){
                case '{':
                case'[':
                case'(':
                    brackets.push(elem);
                    break;
                case'}':
                    Character top=brackets.pop();
                    if(top==null)
                    {
                        System.out.println("匹配错误");
                        return false;
                    }

                    if(top=='{')
                        break;
                    else
                    {
                        System.out.println("匹配错误");
                        return false;
                    }
                case']':
                    top = brackets.pop();
                    if(top==null)
                    {
                        System.out.println("匹配错误");
                        return false;
                    }

                    if(top=='[')
                        break;
                    else{
                        System.out.println("匹配错误");
                        return false;
                    }
                case')':
                    top=brackets.pop();
                    if(top==null)
                    {
                        System.out.println("匹配错误");
                        return false;
                    }

                    if(top=='(')
                        break;
                    else
                    {
                        System.out.println("匹配错误");
                        return false;
                    }
                default:
                    break;
            }
        }
        System.out.print("走到这里了");
        if(brackets.isEmpty())
        {
            System.out.println("匹配成功");
            return true;
        }
        else{
            System.out.println("匹配错误");
            return false;
        }

}
    public static void main(String args[])
    {
       String s="{{}}({})[]";
       isok(s);
    }
}

上文中关于Character型stack,pop出来的元素:

if(top==‘{’)
补充如下:
在这里插入图片描述

### Java实现四则运算表达式的解析和计算 #### 解析与计算框架概述 为了有效地处理复杂的数学表达式,可以采用递归调用来逐步简化并解决嵌套的子表达式。通过这种方法,能够灵活应对含有括号以及不同优先级的操作符的情况。 当遇到括号的复杂表达式时,`parseFormula` 函数负责识别最内层的一对圆括号,并将其内部的内容作为新的独立表达式传递给自己继续执行相同逻辑直到完全去除所有层次的括号[^1]。一旦去掉了所有的括号,就轮到 `parseFourArithmetic` 来接管剩余的任务了——它会区分出仅含单一类型的算术操作(比如全是加减或是全为乘除),或者是混合型情况下的进一步拆分。 对于简单的线性序列化后的表达式片段,`parseSimpleFormula` 将按照从左至右的原则依次应用相应的运算法则完成数值转换过程。每当某个局部区域内的运算结束之后,其结果会被存储起来供后续更高级别的运算引用,从而确保整个公式的连贯性和准确性。 ```java public class ExpressionEvaluator { private static final Map<Character, Integer> precedenceMap; static { precedenceMap = new HashMap<>(); precedenceMap.put('+', 1); precedenceMap.put('-', 1); precedenceMap.put('*', 2); precedenceMap.put('/', 2); } public double evaluate(String expression) throws Exception { Deque<Double> numStack = new LinkedList<>(); Deque<Character> optStack = new LinkedList<>(); int i = 0; while (i < expression.length()) { char ch = expression.charAt(i); if (Character.isDigit(ch)) { // 数字入 StringBuilder sb = new StringBuilder(); while ((i < expression.length() && Character.isDigit(expression.charAt(i))) || '.' == expression.charAt(i)) sb.append(expression.charAt(i++)); numStack.push(Double.parseDouble(sb.toString())); continue; } if ('(' == ch) { // 左括号直接压入操作符 optStack.push(ch); } else if (')' == ch) { // 右括号触发一次完整的计算直至遇见对应的左括号 while (!optStack.isEmpty() && '(' != optStack.peek()) calculate(numStack, optStack); if(optStack.isEmpty()){ throw new RuntimeException("缺少匹配的左括号"); } optStack.pop(); // 移除配对成功的左括号 }else{ // 非括号字符视为运算符 while(!optStack.isEmpty() && precedenceMap.getOrDefault(ch, 0) <= precedenceMap.getOrDefault(optStack.peek(), 0)){ calculate(numStack,optStack); } optStack.push(ch); } ++i; } while (!optStack.isEmpty()) calculate(numStack, optStack); return numStack.pop(); } private void calculate(Deque<Double> nums, Deque<Character> ops){ Double b = nums.pop(); Double a = nums.pop(); Character op = ops.pop(); switch(op){ case '+': nums.push(a+b); break; case '-': nums.push(a-b); break; case '*': nums.push(a*b); break; case '/': if(b==0){ throw new ArithmeticException("Divide by zero error."); } nums.push(a/b); break; } } } ``` 上述代码展示了基于双端队列(`Deque`)模拟堆行为来管理数字项和操作符之间的关系,以此达到支持括号四则运算的目的。这里的关键在于维护好两个不同的:一个是用于暂存待参与运算的具体数值;另一个则是记录等待被执行的各种基本运算指令。随着遍历输入串的过程中不断调整这两个容器的状态变化,最终实现了预期的功能需求[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值