Java栈的运用之中缀表达式求值详解

 更新时间:2022年11月22日 08:36:57   作者:未见花闻  
本文来介绍一题中缀表达式求值的问题,就是给定一个中缀计算式,编写程序将这个式子运算结果给计算出来,其实和后缀表达式的思路差不多,都是栈的运用问题,感兴趣的可以了解一下

栈运用题:中缀表达式求值

题目详情

给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。

注意:

数据保证给定的表达式合法。

题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现。

题目保证表达式中所有数字均为正整数。

题目保证表达式在中间计算过程以及结果中,均不超过 231−1。

题目中的整除是指向 0 取整,也就是说对于大于 0 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1。

C++和Java中的整除默认是向零取整;Python中的整除//默认向下取整,因此Python的eval()函数中的整除也是向下取整,在本题中不能直接使用。

输入格式

共一行,为给定表达式。

输出格式

共一行,为表达式的结果。

数据范围

表达式的长度不超过105

输入样例:

(2+2)*(1+1)

输出样例:

8

解题思路

对于这道题,我们可以使用两个栈,一个栈nums用来存运算数,另外一个栈ops可以用来存运算符,但是运算符之间是存在优先级的,我们还可以使用一个哈希表来储存每个运算符的优先级,可以使用数字的大小表示优先级的高低。

第一步,遍历字符串,可能会遇到以下情况:

1)遇到数字,将数组储存到栈nums中。

2)遇到(,直接将(存到栈ops中。

3)遇到),取出栈顶两个数,取出栈顶运算符,进行运算,将运算结果存入栈nums中,如果栈ops栈顶不为空并且栈顶元素不为(,则继续运算,直到栈为空或者栈顶元素为(为止。

4)遇到运算符+,-,*,/,检查栈ops栈顶运算符优先级是否大于或等于遍历遇到的运算符,如果优先级大,则进行运算操作(同上取出栈nums两个数,栈ops一个操作符进行运算,并将结果储存到nums中),然后继续检查,直到栈ops为空或者ops栈顶元素为(,最后将遍历的运算符入栈ops。

第二步,检查是否运算完成。

字符串遍历完成后,此时运算不一定结束,检查栈ops是否为空,不为空继续进行运算操作,直到栈ops为空为止,最终nums剩余的一个数就是运算结果。

对于运算符优先级的判断我们可以通过建立哈希表,将运算符映射一个数字,其中数字越大就表示优先级越大。

实现代码

Java版本实现:

import java.util.*;

class Main {
    //栈nums 存运算数
    private static Deque<Integer> nums = new ArrayDeque<>();
    //栈ops 存运算符
    private static Deque<Character> ops = new ArrayDeque<>();
    
    //哈希表用来映射运算符优先级
    private static HashMap<Character, Integer> hash = new HashMap<>();
    
    //初始化哈希表
    static {
        hash.put('+', 1);
        hash.put('-', 1);
        hash.put('*', 2);
        hash.put('/', 2);
    }
    
    //判断某个字符是否是数字
    private static boolean isDigit(char c) {
        return c >= '0' &&c <= '9';
    }
    
    //实现运算方法
    private static void eval() {
        //去除第二个运算数
        int b = nums.pollLast();
        //取出第一个运算数
        int a = nums.pollLast();
        //取出运算符
        char op = ops.pollLast();
        
        //判断符号,对应进行运算
        if (op == '+') nums.offerLast(a + b);
        else if (op == '-') nums.offerLast(a - b);
        else if (op == '*') nums.offerLast(a * b);
        else if (op == '/') nums.offerLast(a / b);
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        String s = sc.nextLine();
        
        char[] cs = s.toCharArray();
        
        for (int i = 0; i < cs.length; i++) {
            char c = cs[i];
            
            if (isDigit(c)) {
                //遍历的字符为数字,取出完整的数字放在数组当中
                int ret = c - '0';
                int j = i + 1;
                while (j < cs.length && isDigit(cs[j])) {
                    ret = ret * 10 + (cs[j] - '0');
                    j++;
                }
                //更新i
                i = j - 1;
                //将数字入栈
                nums.offerLast(ret);
            } else if (c == '(') {
                //遇到(,直接入栈ops
                ops.offerLast(c);
            } else if (c == ')') {
                //遇到),进行运算操作,直到栈顶遇到(为止
                while (!ops.isEmpty() && ops.peekLast() != '(') eval();
                //遇到(,将(出栈
                ops.pollLast();
            } else {
                //遇到运算符,则比较优先级,如栈顶运算符优先级大,则进行运算,直到栈为空或栈顶运算符较小或栈顶运算符为(
                while (!ops.isEmpty() && ops.peekLast() != '(' && hash.get(ops.peekLast()).compareTo(hash.get(c)) >= 0) eval();
                
                //将当前运算符入栈
                ops.offerLast(c);
            }
        }
        
        //检查ops栈内是否还有运算符,如果还有,则表示运算还没结束,继续运算,直到ops栈无运算符为止
        while (!ops.isEmpty()) eval();
        
        //输出nums栈顶元素,即是最终运算结果
        System.out.println(nums.peekLast());
    }
}

C++版本实现:

include <iostream>
#include <stack>
#include <unordered_map>
#include <algorithm>
#include <string>

using namespace std;

//栈1 存储元素
stack<int> nums;
//栈2 存储操作符号
stack<char> ops;


//哈希表 用来存储运算符优先级
unordered_map<char, int> pri = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};

void eval()
{
    //取第二个操作数
    int b = nums.top();
    nums.pop();
    //取第一个操作数
    int a = nums.top();
    nums.pop();
    
    //取操作符
    char op = ops.top();
    ops.pop();
    
    //进行运算
    if (op == '+') nums.push(a + b);
    else if (op == '-') nums.push(a - b);
    else if (op == '*') nums.push(a * b);
    else if (op == '/') nums.push(a / b);
    
    //cout << a << " " << op << " " << b << "=";
    
    //cout << nums.top() << endl;
}

int main()
{
    string s;
    cin >> s;
    
    for (int i = 0; i < s.size(); i++) 
    {
        char c = s[i];
        if (isdigit(c)) 
        {
            //字符为数字,将该数字放入到储存数字的栈中
            int j = i + 1;
            int ret = s[i] - '0';
            while (j < s.size() && isdigit(s[j]))
            {
                ret = ret * 10 + (s[j] - '0');
                j++;
            }
            //更新i
            i = j  - 1;
            nums.push(ret);
        } else if (c == '(') 
        {
            ops.push(c);
        } else if (c == ')') 
        {
            //遇到右括号对栈元素进行运算,直到遇到(为止
            while (ops.size() > 0 && ops.top() != '(') eval();
            ops.pop();
        } else {
            //遇到运算符,比较优先级,如果优先级较高,则进行运算
            while (ops.size() > 0 && ops.top() != '(' && pri[ops.top()] >= pri[c]) eval();
            ops.push(c);
        }
    }
    
    //如果还有剩余运算符 则继续运算
    while (ops.size() > 0) eval();
    //栈顶元素即为最终的运算结果
    cout << nums.top() << endl;
    return 0;
}

以上就是Java栈的运用之中缀表达式求值详解的详细内容,更多关于Java中缀表达式求值的资料请关注脚本之家其它相关文章!

相关文章

  • jasypt 集成SpringBoot 数据库密码加密操作

    jasypt 集成SpringBoot 数据库密码加密操作

    这篇文章主要介绍了jasypt 集成SpringBoot 数据库密码加密操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • Mac M1安装JDK的实战避坑指南

    Mac M1安装JDK的实战避坑指南

    这篇文章主要给大家介绍了关于Mac M1安装JDK避坑的相关资料,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-02-02
  • Mybatis查询返回Map<String,Object>类型的实现

    Mybatis查询返回Map<String,Object>类型的实现

    本文主要介绍了Mybatis查询返回Map<String,Object>类型的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Java跳出多重嵌套循环过程解析

    Java跳出多重嵌套循环过程解析

    这篇文章主要介绍了Java跳出多重嵌套循环过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java设计模式之单例模式实例详解【懒汉式与饿汉式】

    Java设计模式之单例模式实例详解【懒汉式与饿汉式】

    这篇文章主要介绍了Java设计模式之单例模式,简单说明了单例模式的原理并结合具体实例形式分析了单例模式中懒汉式与饿汉式的具体实现与使用技巧,需要的朋友可以参考下
    2017-09-09
  • java多线程教程之如何使用线程池详解

    java多线程教程之如何使用线程池详解

    这篇文章主要给大家介绍了关于java多线程之如何使用线程池的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • java通过Idea远程一键部署springboot到Docker详解

    java通过Idea远程一键部署springboot到Docker详解

    这篇文章主要介绍了java通过Idea远程一键部署springboot到Docker详解,Idea是Java开发利器,springboot是Java生态中最流行的微服务框架,docker是时下最火的容器技术,那么它们结合在一起会产生什么化学反应呢?的相关资料
    2019-06-06
  • Java框架Quartz中的Trigger简析

    Java框架Quartz中的Trigger简析

    这篇文章主要介绍了Java框架Quartz中的Trigger简析,所有类型的trigger都有TriggerKey这个属性,表示trigger的身份;除此之外,trigger还有很多其它的公共属性,这些属性,在构建trigger的时候可以通过TriggerBuilder设置,需要的朋友可以参考下
    2023-11-11
  • Spring Boot中单例类实现对象的注入方式

    Spring Boot中单例类实现对象的注入方式

    这篇文章主要介绍了Spring Boot中单例类实现对象的注入方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Javaweb基础入门HTML之table与form

    Javaweb基础入门HTML之table与form

    HTML的全称为超文本标记语言,是一种标记语言。它包括一系列标签.通过这些标签可以将网络上的文档格式统一,使分散的Internet资源连接为一个逻辑整体。HTML文本是由HTML命令组成的描述性文本,HTML命令可以说明文字,图形、动画、声音、表格、链接等
    2022-03-03

最新评论