通过栈实现算术表达式的计算

2023-11-14

最近在看数据结构的栈,其中有一节为栈应用到算术表达式的计算,接下来我讲举例说明如何用栈去计算,如有不对的地方,请各位大神指教。

1、定义操作符的优先级,"("作为栈顶操作符时优先级仅高于"=",")"作为栈顶操作符时优先级是最高的,"*"和"/"优先级一样,但是一个作为栈顶的一个作为当前的操作符,那么栈顶的操作符的优先级就大于当前的操作符的优先级,"+"和"-"类似,但"+"和"-"无论是栈顶还是当前的优先级都小于"*"和"/";

2、解析算术表达式。将算术表达式由字符串解析成每个元素;

3、扫描算术表达式,如果当前元素是操作数,则直接进操作数栈,如果当前元素是操作符,则从右操作符优先级列表中找到该操作符的优先级currentRank,并从左操作符优先级列表中找到栈顶操作符的优先级topRank,如果当前操作符优先级高于栈顶操作符优先级则当前扫描到的操作符直接进操作符栈;如果当前操作符优先级低于栈顶操作符优先级,则判断当前操作符是否为")",如果不为")",则栈顶操作符出栈,并且操作数栈先后出栈顶两个操作数,并利用出栈的操作符计算结果,并将结果压入操作数栈中,一直到当前操作符的优先级高于栈顶操作符的优先级截止,然后将当前操作符压入操作符栈中;如果为")",则栈顶操作符出栈,并且操作数栈先后出栈顶两个操作数,并利用出栈的操作符计算结果,并将结果压入操作数栈中,一直到栈顶操作符为"("截止,然后将"("出栈。

4、当算术表达式扫描完成之后,依次将操作符栈栈顶操作符出栈,并在同时将操作数栈栈顶两个操作数相继出栈,计算结果,将结果压入操作数栈中。

以上是整个计算步骤,下面是我自己编写的java程序。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;


public class Stack {


private static LinkedList<String> operandStack; //操作数栈,静态成员函数里的成员变量必须为static
private static LinkedList<String> operatorStack; //操作符栈
private static Map<String, Integer> operatorLRank; //左操作符优先级
private static Map<String, Integer> operatorRRank; //右操作符优先级
private static List<String> expList; //算术表达式列表
private static List<Integer> eTypeList; //每个元素的类型,0为数字,1为操作符
private static Set<Integer> indexSet; //操作符位置集合
public static void main(String[] args) {
String exp="5*2^(14+2*2-6*3)-(8-9*2)*2";
// String exp="2-(14+2*2-6*3)*3";

initStack();
initOperatorRanks();
analysis(exp);
scanExp();
System.out.println("计算结果: "+operandStack.getLast());
}

/**
* 初始化栈
*/
private static void initStack(){
operandStack=new LinkedList<String>();
operatorStack=new LinkedList<String>();
operatorLRank=new HashMap<String, Integer>();
operatorRRank=new HashMap<String, Integer>();
expList=new ArrayList<String>();
eTypeList=new ArrayList<Integer>();
}

/**
* 初始化操作符等级
*/
private static void initOperatorRanks(){
//初始化左操作符,也就是作为栈顶操作符,由于加减是按从左到右的顺序计算的,所以"+","-"作为栈顶操作符时比扫描的优先级大
operatorLRank.put("=", 0);
operatorLRank.put("(", 1);
operatorLRank.put("+", 3);
operatorLRank.put("-", 3);
operatorLRank.put("*", 5);
operatorLRank.put("/", 5);
operatorLRank.put("^", 6);
operatorLRank.put(")", 7);
//初始化右操作符,作为当前扫描的操作符
operatorRRank.put("=", 0);
operatorRRank.put(")", 1);
operatorRRank.put("+", 2);
operatorRRank.put("-", 2);
operatorRRank.put("*", 4);
operatorRRank.put("/", 4);
operatorRRank.put("^", 6);
operatorRRank.put("(", 7);
}

/**
* 解析算术表达式
*/
private static void analysis(String exp){
//首先找出算术表达式中所有非数字的操作符,并记录位置
indexSet=new TreeSet<Integer>();
for(int i=0;i<exp.length();i++){
if(!isDigital(exp.charAt(i))){
indexSet.add(i);
}
}
//遍历set将两个位置中的数字取出
Iterator<Integer> it=indexSet.iterator();
int endIndex=it.next();
if(!exp.substring(0, endIndex).isEmpty()){
expList.add(exp.substring(0, endIndex));
eTypeList.add(0);
}
while(it.hasNext()){
int beginIndex=endIndex;
endIndex=it.next();
expList.add(String.valueOf(exp.charAt(beginIndex)));
eTypeList.add(1);
String digital=exp.substring(beginIndex+1, endIndex);
if(!digital.isEmpty()){
expList.add(digital);
eTypeList.add(0);
}
}
expList.add(String.valueOf(exp.charAt(endIndex)));
eTypeList.add(1);
if(!exp.substring(endIndex+1, exp.length()).isEmpty()){
expList.add(exp.substring(endIndex+1, exp.length()));
eTypeList.add(0);
}

}

/**
* 判断字符是否为数字
* @param ch
* @return
*/
private static boolean isDigital(char ch){
//0的ascii是48,9的ascii是57
if(ch>=48 && ch<=57){
return true;
}else{
return false;
}
}

private static void scanExp(){
pushStack(operatorStack, "="); //首先将最低等级的=压入操作符栈中
for(int i=0;i<expList.size();i++){
String e=expList.get(i);
//如果是操作符
if(eTypeList.get(i)==1){
/**
* 比较当前操作符与栈顶操作符的优先级,如果当前操作符优先级高于栈顶,则直接入栈
* 如果小于,则栈顶操作符出栈,并且操作数栈出栈顶两个元素,进行计算,并入栈,
* 直到当前操作符的优先级高于栈顶的优先级
*/
int currentRank=operatorRRank.get(e);//从右操作符栈中找出当前操作符的优先级
String topE=getStackTop(operatorStack);
int topRank=operatorLRank.get(topE);//从左操作符栈中找出栈顶操作符的优先级
//如果当前操作符大于栈顶操作符
if(currentRank>topRank){
pushStack(operatorStack, e);
}else{
if(!")".equals(e)){
while(currentRank<topRank){
computePush(topE);
topE=getStackTop(operatorStack);
topRank=operatorLRank.get(topE);//从左操作符栈中找出栈顶操作符的优先级
}
pushStack(operatorStack, e);
}else{
while(!"(".equals(topE)){
computePush(topE);
topE=getStackTop(operatorStack);
topRank=operatorLRank.get(topE);//从左操作符栈中找出栈顶操作符的优先级
}
outStack(operatorStack); //将"("出栈
}
}
}
//如果是操作数
else if(eTypeList.get(i)==0){
pushStack(operandStack, e);
}

print(operatorStack, operandStack);
}
//当扫描完成之后将操作符栈和操作数栈全部出栈
Iterator<String> it=operatorStack.iterator();
while(it.hasNext()){
String topE=getStackTop(operatorStack);
if(!"=".equals(topE)){
computePush(topE);
}else{
break;
}
}
print(operatorStack, operandStack);
}
/**
* 操作数压栈
*/
private static void pushStack(LinkedList<String> stack, String e){
stack.addLast(e);
}

/**
* 操作数出栈
*/
private static void outStack(LinkedList<String> stack){
stack.removeLast();
}

/**
* 得到栈顶元素
* @param stack
*/
private static String getStackTop(LinkedList<String> stack){
return stack.getLast();
}

/**
* 如果当前操作符优先级小于栈顶优先级则栈顶操作符出栈,操作数栈出栈顶的两个元素并计算结果
* @param topE
*/
private static void computePush(String topE){
outStack(operatorStack); //操作符出栈顶元素
String e1=getStackTop(operandStack);
outStack(operandStack);
String e2=getStackTop(operandStack);
outStack(operandStack);

int res=compute(e2, topE, e1);
pushStack(operandStack, String.valueOf(res));
}
/**
* 计算两个元素的算术结果
* @param e1
* @param operator
* @param e2
* @return
*/
private static int compute(String e1, String operator, String e2){
int ie1=Integer.valueOf(e1);
int ie2=Integer.valueOf(e2);
if("+".equals(operator)){
return ie1+ie2;
}else if("-".equals(operator)){
return ie1-ie2;
}else if("*".equals(operator)){
return ie1*ie2;
}else if("/".equals(operator)){
return ie1/ie2;
}else if("^".equals(operator)){
return (int)Math.pow(ie1, ie2);
}else{
return 0;
}
}

private static void print(List list1, List list2){
for(int i=0;i<list1.size();i++){
if(i>0){
System.out.print(",");
}
System.out.print(list1.get(i));
}
for(int i=0;i<30-list1.size();i++){
System.out.print(" ");
}
for(int i=0;i<list2.size();i++){
if(i>0){
System.out.print(",");
}
System.out.print(list2.get(i));
}
System.out.println();
}


}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过栈实现算术表达式的计算 的相关文章

随机推荐

  • 自定义指令的说明和注册

    自定义指令说明 Vue3 除了核心功能默认内置的指令 v model 和 v show Vue 也允许注册自定义指令 v xxx 注意 代码复用和抽象的主要形式是组件 然而 有的情况下 你仍然需要对普通 DOM 元素进行底层操作 这时候就会
  • Linux/多线程的同步与互斥

    线程安全 多个执行流对资源进行争抢访问 但不会产生数据二义性 线程安全的实现 同步 互斥 同步 通过条件判断实现对临界资源访问的合理性 互斥 通过同一时间对临界资源的唯一访问 实现对临界资源访问的安全性 互斥锁 互斥的实现 互斥锁 在多任务
  • 第一次使用Eclipse:编写简单的Java小程序

    通过前部分的学习 了解了Java的安装和配置 那么从现在开始 要开始自己着手编写Java程序 学习一门编程语言 学会编写的第一个程序一般都是写一个输出 hello World 语句的小程序来表示自己开始学习这门语言 那么这篇教程也不例外 因
  • fsnotify 与 too many open files

    fsnotify fsnotify 是用来监听文件 目录变化的一个 golang 开源库 在 Linux 系统使用中 遇到了too many open files问题 首次尝试 通常 有 2 处配置太小 会触发too many open f
  • 最惊艳的sql

    select from girls where age between 18 and 20 and boyfriend is null order by cup desc
  • 不管人工智能发展如何 开发者都有必要了解 Linux 内核

    Linux内核在计算机世界的地位有目共睹 称它为计算机世界的基石也不为过 而且它还是全球最大的开源项目 几乎最知名的科技公司都参与其中 包括谷歌 Red Hat SUSE Intel Facebook 甲骨文和华为等 当然还包括Linux的
  • 将cmd中输出数据 保存为TXT文本

    原文 http blog sina com cn s blog 6d2d58cd0100x7zw html 在使用Windows XP中的cmd exe工具时 有时候我们想要把我们的输入命令及结果保存起来 但是用复制的方法过于麻烦 有时输出
  • LeetCode 热题 HOT 100:滑动窗口专题

    LeetCode 热题 HOT 100 https leetcode cn problem list 2cktkvj 文章目录 3 无重复字符的最长子串 128 最长连续序列 239 滑动窗口最大值 438 找到字符串中所有字母异位词 3
  • JFLex和JavaCUP简单使用

    由于需要使用到doris中的sql parser功能 所以决定使用其定义好的flex文件和cup文件 生成自己sqlscanner和parser类 步骤如下 1 下载JFlex和JavaCUP程序 路径分别为 https www jflex
  • 机械制造与自动化涉及使用计算机吗,论机械设计制造及自动化中计算机技术

    将计算机技术运用到机械设计制造中 大大提高了机械设计制造智能化水平 在机械设计制造中占据很重要的位置 但我国机械制造设计水平同国外发达国家相比 还存在一定的距离 若是可以加大对计算机技术的研究和探索 对机械制造行业的发展是非常有利的 1机械
  • Flowable入门系列文章29 - Activity解读 05

    1 消息开始事件 描述 甲消息开始事件可用于使用已命名的信息来启动一个过程实例 这有效地允许我们使用消息名称从一组替代开始事件中选择正确的开始事件 在部署具有一个或多个消息启动事件的流程定义时 应考虑以下注意事项 消息开始事件的名称在给定的
  • 机器学习实战:Python基于支持向量机SVM-RFE进行分类预测(三)

    文章目录 1 前言 1 1 支持向量机的介绍 1 2 支持向量机的应用 2 demo数据集演示 2 1 导入函数 2 2 构建数据集拟合 2 3 预测模型及可视化 3 实例演示分类 非SVM 3 1 导入函数和数据 3 2 简单线性分类 3
  • 剑指offer Java实现 第五题

    第五题 请实现一个函数 将一个字符串中的每个空格替换成 20 例如 当字符串为We Are Happy 则经过替换之后的字符串为We 20Are 20Happy 实现代码 public static String replaceSpace
  • MSCOCO数据集格式转化成VOC数据集格式

    MSCOCO数据集格式转化成VOC数据集格式 转载请注明原出处 http blog csdn net ouyangfushu article details 79543575 作者 SyGoing QQ 2446799425 SSD目标检测
  • [springmvc学习]8、JSR 303验证及其国际化

    目录 简介 常见注解 基本使用 BindResult获取异常信息 自定义提示信息 取消属性绑定 总结 简介 JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架 它已经包含在 JavaEE 中 我们可以通过注解的方式来指
  • SFTP报错,sftp couldn‘t stat remote file:No such file or directory

    原因 使用sftp进行文件传输时 需要连接到远程服务器的root用户上去 这就导致了另一个问题 在命令行使用su命令并输入root用户密码可以切换到root用户 但是使用sftp连接root用户 会连接失败 同类型的问题也有使用xshell
  • IDE介绍

    集成开发工具 gt gt gt IDE 编码工具取代了简单的记事本工具 辅助程序员编写源代码的常用高效编写工具 类似word 我们写文档会打开word文档来编写 代码也同样需要借助工具来开发 常见的编辑工具有记事本 sublime text
  • SD HOST——(一)SD简介

    Micro SD有九个引脚 TF卡只要八个 少一个地 CLK CMD 双向口 用于发命令和接收response VDD GND GND D3 D2 D1 D0 D3 D0不一定传输的是数据 读SD内部寄存器状态也可以从D3 30输出 CMD
  • Pytorch并行训练方法-单机多卡

    简单方便的 nn DataParallel DataParallel 可以帮助我们 使用单进程控 将模型和数据加载到多个 GPU 中 控制数据在 GPU 之间的流动 协同不同 GPU 上的模型进行并行训练 细粒度的方法有 scatter g
  • 通过栈实现算术表达式的计算

    最近在看数据结构的栈 其中有一节为栈应用到算术表达式的计算 接下来我讲举例说明如何用栈去计算 如有不对的地方 请各位大神指教 1 定义操作符的优先级 作为栈顶操作符时优先级仅高于 作为栈顶操作符时优先级是最高的 和 优先级一样 但是一个作为