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

目录
  • 栈运用题:中缀表达式求值
    • 题目详情
    • 解题思路
    • 实现代码

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

题目详情

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

注意:

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

题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-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中缀表达式求值的资料请关注我们其它相关文章!

(0)

相关推荐

  • java实现中缀表达式转后缀的方法

    本文先给出思路与方法,最后将给出完整代码: 算法综述: 一.中缀表达式转后缀表达式: 1.中缀表达式要转后缀表达式,首先需要两个Stack(栈),其中一个应用于存放字符,另一个用于存放数字. 2.读到数字直接存入数字栈中,读到字符时,要咸鱼栈内前一元素(字符)进行比较,当当前(要存入的字符)优先级大于迁移字符时才存入,否则(>=)要仿佛将栈内元素弹出,并依次存入数字栈中. 提示:'(' 的优先级默认比所有字符都小.所有字符都可以存在它后面:同时夜笔所有字符都大,可以存在所有字符后面 3.遇到 '

  • Java中缀表达式转后缀表达式流程详解

    目录 一.栈 1.栈的基本介绍 2.栈的底层实现 二.中缀表达式转后缀表达式 1.拆解中缀表达式 2.中缀转后缀的算法 3.中缀转后缀代码解析 4.对后缀表达式进行计算 一.栈 1.栈的基本介绍 栈是⼀个先⼊后出的有序列表.栈(stack)是限制线性表中元素的插⼊和删除只能在线性表的同⼀端进⾏的⼀种特殊线性表.允许插⼊和删除的⼀端,为变化的⼀端,称为栈顶(Top),另⼀端为固定的⼀端,称为栈底(Bottom). 根据栈的定义可知,最先放⼊栈中元素在栈底,最后放⼊的元素在栈顶,⽽删除元素刚好相反,

  • java数据结构与算法之中缀表达式转为后缀表达式的方法

    本文实例讲述了java数据结构与算法之中缀表达式转为后缀表达式的方法.分享给大家供大家参考,具体如下: //stack public class StackX { private int top; private char[] stackArray; private int maxSize; //constructor public StackX(int maxSize){ this.maxSize = maxSize; this.top = -1; stackArray = new char[

  • Java中缀表达式转后缀表达式实现方法详解

    本文实例讲述了Java中缀表达式转后缀表达式实现方法.分享给大家供大家参考,具体如下: 本文先给出思路与方法,最后将给出完整代码 项目实战: https://www.jb51.net/article/158335.htm 算法综述: 一.中缀表达式转后缀表达式: 1.中缀表达式要转后缀表达式,首先需要两个Stack(栈),其中一个应用于存放字符,另一个用于存放数字. 2.读到数字直接存入数字栈中,读到字符时,要咸鱼栈内前一元素(字符)进行比较,当当前(要存入的字符)优先级大于迁移字符时才存入,否

  • 详解Java中缀表达式的实现

    目录 1.概念 2.算法流程 3 代码实现 1.概念 什么是中缀表达式,什么是后缀表达式? 从小学开始学习的四则运算,例如:3+(5*(2+3)+7) 类似这种表达式就是中缀表达式.中缀表达式人脑很容易理解,各个算符的优先级,人脑也很容易判断,先算括弧里的,再算*,再算+,- 但是这种表达式很不利于计算机计算,通过某种方式把前缀表达式转换为后缀表达式方便计算机进行计算,如3+(5*(2+3)+7)的后缀表达式就是3,5,2,3,+,*,7,+, +.这个表达式计算机很容易计算,为什么容易计算,通

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

    目录 栈运用题:中缀表达式求值 题目详情 解题思路 实现代码 栈运用题:中缀表达式求值 题目详情 给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值. 注意: 数据保证给定的表达式合法. 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现. 题目保证表达式中所有数字均为正整数. 题目保证表达式在中间计算过程以及结果中,均不超过 231−1. 题目中的整除是指向 0 取整

  • C++表达式求值详解

    目录 一.细节处理: 1.注意负数 因此要进行字符串预处理 2.考虑除数为0 3.原字符串再加上一个定界符 '#' 4.优先级: 二.知识要点: 三.完整源码: 四.测试结果: 总结 一.细节处理: 1.注意负数 因此要进行字符串预处理 string format(string str) { int len = str.length(); for (int i = 0; i < len; i++) { if (str[i] == '-') { if (i == 0) { str.insert(0

  • C#函数式编程中的惰性求值详解

    惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术.首先需要说明的是C#语言小部分采用了非严格求值策略,大部分还是严格求值策略.首先我们先演示非严格求值策略的情况,我们先在控制台项目中写一个DoOneThing方法. 然后在Main方法中写入下面这串代码: 然后我们运行程序,会发现DoOneThing方法并没有执行.当然这看起来也很正常,因为这是或,并且第一个已经是true了.整个表达式就是true了,自

  • Java陷阱之慎用入参做返回值详解

    正常情况下,在Java中入参是不建议用做返回值的.除了造成代码不易理解.语义不清等问题外,可能还埋下了陷阱等你入坑. 问题背景 比如有这么一段代码: @Named public class AService { private SupplyAssignment localSupply = new SupplyAssignment(); @Inject private BService bervice; public List<Supply> calcSupplyAssignment() Lis

  • Java如何从json字符串中获取某个值详解

    目录 Java从json串中获取某个值 使用org.json进行解析 使用com.alibaba.fastjson进行解析 总结 Java从json串中获取某个值 java对象是不能直接传输,只有json对象 转成字符串 可以进行传输 故 传输中都是json进行的 接收到json数据之后java在进行解析转换成为字符串.且json适用于很多语言之间的传输 json本质上就是一个map. 对应有两种json进行解析 首先就是先对json的合法性进行验证 是否可以进行解析 点击这里 进行json解析

  • JavaScript数据结构中栈的应用之表达式求值问题详解

    本文实例讲述了JavaScript数据结构中栈的应用之表达式求值问题.分享给大家供大家参考,具体如下: 下面来谈一个比较经典的表达式求值问题,这个问题主要是设计到操作符的优先级.我们通常看到的表达式都是中缀表达式,存在很多优先级差别,而后缀表达式则没有这些优先级问题.下面先看看两种表达式的区别. 中缀表达式:a*b+c*d-e/f      后缀表达式:ab*cd*+ef/- 从中缀表达式转换到后缀表示式是很难实现的,我们这里可以通过栈的思想来实现.下面进行详细的介绍是什么样的思想: 在对一个中

  • C语言中栈和队列实现表达式求值的实例

    C语言中栈和队列实现表达式求值的实例 实现代码: #include<stdio.h> #include<stdlib.h> #define OK 1 #define ERROR 0 #define STACK_SIZE 20 #define STACK_INCREMENT 10 #define QUEUE_SIZE 20 typedef int Status; typedef char StackElemtype; typedef struct Stack{ StackElemty

  • java实现任意四则运算表达式求值算法

    本文实例讲述了java实现任意四则运算表达式求值算法.分享给大家供大家参考.具体分析如下: 该程序用于计算任意四则运算表达式.如 4 * ( 10 + 2 ) + 1 的结果应该为 49. 算法说明: 1. 首先定义运算符优先级.我们用一个 Map<String, Map<String, String>> 来保存优先级表.这样我们就可以通过下面的方式来计算两个运算符的优先级了: /** * 查表得到op1和op2的优先级 * @param op1 运算符1 * @param op2

  • C++利用链栈实现表达式求值

    本文实例为大家分享了C++利用链栈实现表达式求值的具体代码,供大家参考,具体内容如下 #include<iostream.h> typedef int Status; typedef char Cstack; #define OK 1 #define ERROR 0 typedef struct StackNode { Cstack data; struct StackNode *next; }StackNode,*LinkStack; Status InitStack(LinkStack &

随机推荐