首页 > 其他分享 >9.27

9.27

时间:2023-09-27 21:00:12浏览次数:34  
标签:操作数 9.27 operatorStack precedence 运算符 operandStack expression

今天实现了课堂作业上的功能代码,实现了对于二三四年级题目的出题以及选择,但这其中最让我感到疑惑的是当我将题目内容以字符串的形式保存下来时,我将如何进行题目的运算,前些天刚刚在算法与数据结构中学习通过栈来实现运算符优先级的运算,下面我把代码放到这里

import java.util.Stack;

public class ArithmeticExpressionEvaluator {
    public static void main(String[] args) {
        String expression = "11 / (5 * 2)";  // 替换为你的题目字符串

        double result = evaluateArithmeticExpression(expression);
        System.out.println("表达式计算结果: " + result);
    }

    public static double evaluateArithmeticExpression(String expression) {
        // 移除空格
        expression = expression.replaceAll("\\s", "");

        // 定义操作数栈和运算符栈
        Stack<Double> operandStack = new Stack<>();
        Stack<Character> operatorStack = new Stack<>();

        // 定义运算符优先级
        int[] precedence = new int[256];
        precedence['+'] = 1;
        precedence['-'] = 1;
        precedence['*'] = 2;
        precedence['/'] = 2;

        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);

            if (Character.isDigit(ch)) {
                // 处理操作数
                StringBuilder sb = new StringBuilder();
                while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
                    sb.append(expression.charAt(i));
                    i++;
                }
                i--;
                double operand = Double.parseDouble(sb.toString());
                operandStack.push(operand);
            } else if (ch == '(') {
                // 左括号入栈
                operatorStack.push(ch);
            } else if (ch == ')') {
                // 右括号,弹出括号内的运算符进行计算
                while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
                    evaluateTopOperator(operandStack, operatorStack);
                }
                if (!operatorStack.isEmpty() && operatorStack.peek() == '(') {
                    operatorStack.pop();  // 弹出左括号
                } else {
                    throw new IllegalArgumentException("括号不匹配");
                }
            } else if (isOperator(ch)) {
                // 处理运算符
                while (!operatorStack.isEmpty() && operatorStack.peek() != '(' &&
                        precedence[ch] <= precedence[operatorStack.peek()]) {
                    evaluateTopOperator(operandStack, operatorStack);
                }
                operatorStack.push(ch);
            } else {
                throw new IllegalArgumentException("无效的字符: " + ch);
            }
        }

        // 处理剩余的运算符
        while (!operatorStack.isEmpty()) {
            evaluateTopOperator(operandStack, operatorStack);
        }

        // 返回最终结果
        if (operandStack.size() == 1 && operatorStack.isEmpty()) {
            return operandStack.pop();
        } else {
            throw new IllegalArgumentException("无效的表达式");
        }
    }

    private static boolean isOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }

    private static void evaluateTopOperator(Stack<Double> operandStack, Stack<Character> operatorStack) {
        if (operandStack.size() < 2 || operatorStack.isEmpty()) {
            throw new IllegalArgumentException("无效的表达式");
        }
        double operand2 = operandStack.pop();
        double operand1 = operandStack.pop();
        char operator = operatorStack.pop();
        double result = performOperation(operand1, operator, operand2);
        operandStack.push(result);
    }

    private static double performOperation(double operand1, char operator, double operand2) {
        switch (operator) {
            case '+':
                return operand1 + operand2;
            case '-':
                return operand1 - operand2;
            case '*':
                return operand1 * operand2;
            case '/':
                if (operand2 != 0) {
                    return operand1 / operand2;
                } else {
                    throw new ArithmeticException("除零错误");
                }
            default:
                throw new IllegalArgumentException("无效的操作符");
        }
    }
}
这段代码的作用如下:
expression = expression.replaceAll("\\s", "");

这行代码使用正则表达式,将 expression 中的空格字符去除掉。它使用 replaceAll 方法,第一个参数是表示空格字符的正则表达式 "\\s",第二个参数为空字符串 "",表示将空格字符替换为空。
接下来是变量的定义和初始化:
Stack&lt;Double&gt; operandStack = new Stack&lt;&gt;();
Stack&lt;Character&gt; operatorStack = new Stack&lt;&gt;();

这两行代码分别定义并创建了一个操作数栈 operandStack 和一个运算符栈 operatorStack,它们是用来存储计算过程中的操作数和运算符的栈。
int[] precedence = new int[256];
precedence['+'] = 1;
precedence['-'] = 1;
precedence['*'] = 2;
precedence['/'] = 2;

这段代码定义了一个长度为 256 的整型数组 precedence,它用来表示运算符的优先级。数组的索引对应ASCII码表中的字符,所以可以通过索引来访问相应的运算符的优先级。这里将 + 和 - 的优先级设置为1,* 和 / 的优先级设置为2。这样在后面的表达式计算中,可以根据这个优先级数组判断运算符的优先级。
这段代码是一个用于解析和计算数学表达式的算法的核心部分。它遍历输入的表达式字符串,逐个处理字符,并根据字符的类型执行不同的操作。让我一步一步解释它的功能:

1.for 循环遍历表达式字符串中的每个字符。
2.char ch = expression.charAt(i);:获取当前字符。
3.if (Character.isDigit(ch)):如果当前字符是一个数字,则进入这个分支,处理操作数。


4.StringBuilder sb = new StringBuilder();:创建一个 StringBuilder 对象,用于构建操作数的字符串表示。
5.while (i &lt; expression.length() &amp;&amp; Character.isDigit(expression.charAt(i))):在当前字符是数字且不越界的情况下,循环读取操作数的每个数字字符,将它们添加到 sb 中。
6.i--;:由于在进入循环时 i 会提前递增,因此需要减一以回到正确的索引位置。
7.double operand = Double.parseDouble(sb.toString());:将 sb 中构建的字符串表示解析为双精度浮点数,表示操作数,然后将其压入操作数栈 operandStack 中。


8.else if (ch == '('):如果当前字符是左括号,将其压入运算符栈 operatorStack 中。
9.else if (ch == ')'):如果当前字符是右括号,执行以下操作:


10.while (!operatorStack.isEmpty() &amp;&amp; operatorStack.peek() != '('):循环弹出运算符栈中的运算符,并将其与操作数栈中的操作数进行计算,直到遇到左括号为止。
11.if (!operatorStack.isEmpty() &amp;&amp; operatorStack.peek() == '('):如果运算符栈不为空且栈顶是左括号,则将左括号从运算符栈中弹出,表示成功匹配一个括号对。
12.否则,抛出异常,表示括号不匹配。


13.else if (isOperator(ch)):如果当前字符是运算符,则执行以下操作:


14.while (!operatorStack.isEmpty() &amp;&amp; operatorStack.peek() != '(' &amp;&amp; precedence[ch] &lt;= precedence[operatorStack.peek()]):循环检查运算符栈中的栈顶元素,如果当前运算符的优先级小于或等于栈顶运算符的优先级,并且栈顶运算符不是左括号,则将栈顶运算符弹出,并将它与操作数栈中的操作数进行计算,直到不满足这个条件为止。
15.将当前运算符压入运算符栈 operatorStack 中。


16.else:如果当前字符既不是数字、左括号、右括号,也不是合法的运算符,则抛出异常,表示出现了无效的字符。

这段代码的目的是将中缀表达式中的操作数和运算符分别处理并保存在栈中,同时处理括号,确保正确的运算顺序。在处理完整个表达式后,您将得到一个操作数栈 operandStack 中包含了最终的计算结果。栈 operatorStack 中可能还包含了一些未处理的运算符,需要继续处理。
这段代码是算法的最后一部分,它用于处理最终的运算符栈 operatorStack 中可能剩余的运算符,并返回最终的计算结果。

1.while (!operatorStack.isEmpty()):循环检查运算符栈是否为空,如果不为空,则执行以下操作。
2.evaluateTopOperator(operandStack, operatorStack):调用 evaluateTopOperator 方法来执行栈顶运算符的计算,并更新操作数栈 operandStack 中的值。
3.if (operandStack.size() == 1 &amp;&amp; operatorStack.isEmpty()):检查操作数栈的大小是否为1且运算符栈是否为空,这是一个有效的表达式求值结果的条件。


4.如果满足条件,表示表达式求值成功,将操作数栈中的唯一元素弹出,并作为最终的计算结果返回。
5.如果不满足条件,抛出异常,表示表达式无效,可能缺失操作数或运算符。

这段代码的目的是处理最终的计算步骤,并确保表达式求值的正确性。如果表达式是有效的,最终结果将以双精度浮点数的形式返回。如果表达式无效,将抛出一个异常表示无效表达式的错误。

 

这个函数用于判断一个字符是否为运算符,返回一个布尔值。如果给定的字符是 +-*/ 中的任意一个,它会返回 true,否则返回 false

这个函数用于处理运算符栈中的顶部运算符。它首先检查操作数栈中是否至少有两个操作数,以及运算符栈是否为空。如果不满足这些条件,就会抛出一个 IllegalArgumentException 异常。接着,它从操作数栈中弹出两个操作数和运算符栈中的一个运算符。然后,它调用 performOperation 方法执行具体的运算,并将运算结果推入操作数栈中。

这个函数用于执行具体的运算操作。它接受两个操作数和一个运算符作为参数,并根据运算符执行相应的操作。它使用 switch 语句根据运算符的不同进行不同的操作,包括加法、减法、乘法和除法。如果进行除法操作时除数为零,它会抛出一个 ArithmeticException 异常;如果运算符不是有效的操作符,它会抛出一个 IllegalArgumentException 异常。

标签:操作数,9.27,operatorStack,precedence,运算符,operandStack,expression
From: https://www.cnblogs.com/zzqq1314/p/17734312.html

相关文章

  • 9.27每日总结
    功能框架图:通过绘制功能框架图,可以更清晰地了解企业生产管理系统的各个功能模块之间的关系和流程。┌───────────────┐│产品管理│└───────────────┘┌───────────────┐│订单管理│└───────────────┘┌......
  • 9.27 每日三题
    A-Moore'sLaw思路:快速幂#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong//#defineint__int128#definedoublelongdoubletypedefpair<int,int>PII;typedefpair<string,int>PSI;typedefpair<string,string>PS......
  • 9.27每日总结
    今日学习时间两小时,完成了springboot+vue前后端分离的编程方式,同时第一次咋hi馆的了解到了为什么是前后端分离的项目,前端使用8080端口,后端使用8081端口,通过axios进行连接,今日能够将数据库的内容显示到vue界面中,但是vue的使用还停留在一个交给浅薄的地步,希望之后继续进行学习......
  • 2023.9.27 LGJ Round
    A已知一个字符串\(n\le1e3\)中的若干信息,:\((x,y,z)\)表示\(x\)后缀和\(y\)后缀的\(\text{LCP}=z\).求满足条件的字典序最小的字符串。已知\(a_{x+i}=a_{y+i}(i<z)\),考虑维护并查集,一定相同的在一个集合。然后要处理的是\(a_{x+z}\neqa_{y+z}\)。从前往后填即可。......
  • 9.27(读后感2)
    今天上午去上了英语提升课下午再宿舍看了程序员修炼之道的第三章还补全了一部分出题系统的代码,再b站上看了如何用Java实现文件的存入与导出。读后感:在阅读完第三章之后,我深深地感受到了编程不仅仅是一种技术,更是一种艺术,一种哲学。这一章主要阐述了软件工艺的重要性,其中......
  • 9.27
    packagecom;importjava.util.Random;publicclasstest{publicstaticvoidmain(String[]args){shortm=0,n=0,ov=0;charo='+';Randomrandom=newRandom();for(inti=0;i<50;i++){ov=(short)random.......
  • 9.27算法
    环形链表给你一个链表的头节点head,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从0开始)。注意:pos不作为参数进行传递 。仅仅是为了......
  • 【坚持每日一题9.27】639. 解码方法 II
    一条包含字母 A-Z的消息通过以下的方式进行了编码:‘A’->1‘B’->2…‘Z’->26要解码一条已编码的消息,所有的数字都必须分组,然后按原来的编码方案反向映射回......
  • Use Ansible-2.9.27 Modular on openEuler
    一、UseAnsible-2.9.27Modular onopenEuler1地址https://docs.ansible.com/ansible/latest/collections/index.html 2ad-hoc概述ad-hoc是临时命令,执行完就......
  • Installing Ansible-2.9.27 Simple Use on openEuler
    一、InstallingAnsible-2.9.27SimpleUseonopenEuler1地址https://ansible.comhttps://docs.ansible.comhttps://github.com/ansible/ansible2环境[root@man......