简单四则运算

问题描述

实现一个基本的计算器来计算一个简单的字符串表达式的值。注意事项如下: - 输入是一个字符串表达式(可以假设所给定的表达式都是有效的) - 字符串表达式可以包含的运算符号为:左括号 (, 右括号 ), 加号 +, 减号 - - 可以包含的数字为:非负整数(< 10) - 字符串中不包含空格 - 处理除法 case 的时候,可以直接省略小数部分结果,只保留整数部分参与后续运算 - 请不要使用内置的库函数 eval

思路

首先明确一点,四则运算中乘法和除法的优先级是最高的,所以要优先考虑乘除,加减运算留到最后再去算,加上表达式可以有括号,在将乘除运算完过后要优先把括号中的式子的值计算出来。 那么面对一个带有括号的四则运算表达式,我们怎么进行计算呢?对我们人来说这是很简单的,按照规则一点点算就是了,可是计算机只能从前往后看这个表达式,它是呆板的,怎么把后面的优先级高的计算完再去找前面的优先级低的呢?我们可以利用广为人知的数据结构-栈,来分别存储数字和运算符

ini 复制代码
     static Stack<Character> cal=new Stack<>();
     static Stack<Integer>  number=new Stack<>();

先从前往后遍历一遍表达式,

遇到数字则直接压入数字栈中

遇到乘除运算的时候我们不能直接就取后面的数字来与前面的数组进行运算,因为当遇到4*(2+3*2)这种表达式时,我们只会取到一个左括号,无法计算,所以我们直接将其入栈

遇到加减运算时,我们也不能直接进行计算,因为无法确定两边的数字是否被乘除所占用,或是一个没有被计算完毕的括号表达式,所以也是直接入栈,但是这个时候我们可以看一看运算符栈中是否有乘除运算符,如果有的话,从数字栈中取出两个数进行相应的运算然后再将数字入栈

ini 复制代码
              switch (k) {
                case '(':
                case '/':
                case '*':
                    cal.add(k);
                    break;
                
                case '+':
                if(cal.size()>0){
                    char x=cal.lastElement();
    
                    if(x=='*'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(firstnum*secondnum);
    
                    }else if(x=='/'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(secondnum/firstnum);
                    }
    
                    
                }
                cal.add(k);                    
                    break;
                case '-':
    
                if(cal.size()>0){
                    char x=cal.lastElement();
    
                    if(x=='*'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(firstnum*secondnum);
    
                    }else if(x=='/'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(secondnum/firstnum);
                    }
    
                    
                }
                cal.add(k);
                    break;
                default:
                    number.add(k-48);//小于10的单个字符直接入栈
                    break;
            }
        }
        

如果遇到括号,遇到左括号我们不做任何处理,直接将其入栈,然后继续按照上面的规则进行运算即可,如果遇到的是右括号,我们就需要把这个括号表达式的值给算出来。

遇到右括号后循环的从运算符栈中取运算符,每次取两个数字进行相应的运算(这个时候不考虑优先级了,因为如果有加减运算那么它们前面的乘除运算就一定被计算完毕,如果没有加减运算就不用考虑优先级了),直到取到左括号为止,然后继续遍历表达式

scss 复制代码
            char kk=cal.lastElement();
            cal.pop();
            while(kk!='('){
                Traverse(kk);//不考虑优先级进行运算
                kk=cal.lastElement();
                cal.pop();
            }

利用上面这些操作循环遍历一次表达式,剩下的运算就不用考虑优先级了,不断的从运算符栈中取运算符进行计算即可,最后数字栈中只剩一个数,直接取走返回答案即可

下面放一下完整的代码,有兴趣的可以复制下来去测试着玩一下,如上分析如有错误敬请各位指出

ini 复制代码
public class Main {        
static Stack<Character> cal=new Stack<>();
static Stack<Integer>  number=new Stack<>();
public static int solution(String expression) {
    

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

            char kk=cal.lastElement();
            cal.pop();
            while(kk!='('){
                Traverse(kk);
                kk=cal.lastElement();
                cal.pop();
            }
        }else{
            switch (k) {
                case '(':
                case '/':
                case '*':
                    cal.add(k);
                    break;
                
                case '+':
                if(cal.size()>0){
                    char x=cal.lastElement();
    
                    if(x=='*'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(firstnum*secondnum);
    
                    }else if(x=='/'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(secondnum/firstnum);
                    }
    
                    
                }
                cal.add(k);                    
                    break;
                case '-':
    
                if(cal.size()>0){
                    char x=cal.lastElement();
    
                    if(x=='*'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(firstnum*secondnum);
    
                    }else if(x=='/'){
    
                        cal.pop();
                        int firstnum=number.lastElement();
                        number.pop();
                        int secondnum=number.lastElement();
                        number.pop();
                        number.add(secondnum/firstnum);
                    }
    
                    
                }
                cal.add(k);
                    break;
                default:
                    number.add(k-48);//小于10的单个字符直接入栈
                    break;
            }
        }

    }

    while(cal.size()>0){
        char kk=cal.lastElement();
        cal.pop();            
        Traverse(kk);
    }
    return number.lastElement();
}
public static void Traverse(char kk){
    int firstnum=number.lastElement();
    number.pop();

    int secondnum=number.lastElement();
    number.pop();
    int num=0;
    switch (kk) {
        case '+':
            num=firstnum+secondnum;
            break;
        case '-':
            num=secondnum-firstnum;
            break;
        case '*':
            num=secondnum*firstnum;
            break;
        case '/':
            num=secondnum/firstnum;
            break;

    }
    number.add(num);
}

public static void main(String[] args) {
    // You can add more test cases here
    System.out.println(solution("1+1") == 2);
    System.out.println(solution("3+4*5/(3+2)") == 7);
    System.out.println(solution("4+2*5-2/1") == 12);
    System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);

    System.out.println("请输入一个10以内的加减乘除计算公式");
    Scanner scan=new Scanner(System.in);

    String s=scan.nextLine();
    System.out.println("结果为"+solution(s));
}

}

相关推荐
AlexMercer101213 分钟前
[C++ 核心编程]笔记 4.2.6 初始化列表
开发语言·数据结构·c++·笔记·算法
zzzhpzhpzzz22 分钟前
设计模式——享元模式
算法·设计模式·享元模式
夜雨翦春韭1 小时前
【代码随想录Day54】图论Part06
java·开发语言·数据结构·算法·leetcode·图论
玉树临风ives1 小时前
2024 CSP-J 题解
c++·算法·深度优先·动态规划
hacker7071 小时前
【hacker送书第14期】AI训练师算法与模型训练从入门到精通
人工智能·算法
大山同学1 小时前
Swarm-LIO: Decentralized Swarm LiDAR-inertial Odometry论文翻译
c++·人工智能·算法·去中心化·区块链
玦尘、2 小时前
LeetCode动态规划篇:经典打家劫舍问题
算法·leetcode·动态规划
TimberWill2 小时前
双指针-01-三数之和
数据结构·算法·leetcode
奶茶喵喵叫2 小时前
C语言基本概念----字节与对齐
c语言·算法
南巷逸清风2 小时前
LeetCode 101.对称二叉树
c++·python·算法·leetcode