数据结构Demo——简单计算器

简单计算器

  • 一、项目介绍
  • 二、技术使用
  • 三、具体代码实现
    • 1.前端部分
    • 2.后端部分

一、项目介绍

本项目实现了一个通过网页访问的简单计算器,它可以对带括号的加减乘除表达式进行计算并将计算结果返回给用户,并且可以对用户输入的表达式进行合法性判断,以下是项目的界面展示:
在这里插入图片描述
使用者可以通过点击网页上的按钮来输入一个算数表达式,之后点击等于号便可以将结果展示在界面上,具体效果如下:
在这里插入图片描述

二、技术使用

在这个计算器中主要使用了前端html,css,JavaScript,后端spring boot以及数据结构中栈的使用方式与相关的算法。

  • 在前端中使用了html来对界面进行了整体的布局,然后使用了css来对界面效果做了美化,最后使用JavaScript来实现每个按钮的点击事件,并且通过Ajax将请求参数发给后台服务器,然后将后台处理的结果接收并处理,最后展示给用户。
  • 在后端中主要使用了spring boot框架来搭建一个简单的服务器,并对前端发来的请求进行处理,最后将处理的结果返回给前端。
  • 在处理表达式的时候主要使用了数据结构中有关栈的一些知识,通过对栈的使用来对表达式进行计算。

三、具体代码实现

1.前端部分

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>计算器</title><link rel="stylesheet" href="./css/style.css">
</head>
<body><div class="container"><div class="calculator dark"><div class="display-screen"><div id="display"></div></div><div class="buttons"><table><tr><td><button class="btn-operator" id="clear">C</button></td><td><button class="btn-operator" id="/">&divide;</button></td><td><button class="btn-operator" id="*">&times;</button></td><td><button class="btn-operator" id="backspace"><</button></td></tr><tr><td><button class="btn-number" id="7">7</button></td><td><button class="btn-number" id="8">8</button></td><td><button class="btn-number" id="9">9</button></td><td><button class="btn-operator" id="-">-</button></td></tr><tr><td><button class="btn-number" id="4">4</button></td><td><button class="btn-number" id="5">5</button></td><td><button class="btn-number" id="6">6</button></td><td><button class="btn-operator" id="+">+</button></td></tr><tr><td><button class="btn-number" id="1">1</button></td><td><button class="btn-number" id="2">2</button></td><td><button class="btn-number" id="3">3</button></td><td rowspan="2"><button class="btn-equal" id="equal" onclick="submit()">=</button></td></tr><tr><td><button class="btn-operator" id="(">(</button></td><td><button class="btn-number" id="0">0</button></td><td><button class="btn-operator" id=")">)</button></td></tr></table></div></div></div><script src="./js/script.js"></script>
</body>
</html>

以上为html部分的代码,主要是对使用者的界面进行了整体布局,确定了各个按钮的位置与功能。

*{margin: 0;padding: 0;box-sizing: border-box;outline: 0;transition: all 0.5s ease;
}
body{font-family: sans-serif;
}
a{text-decoration: none;color: #fff;
}
body{background-image: linear-gradient(to bottom right, rgb(10, 88, 232), rgb(41, 231, 225));
}
.container{height: 100vh;width: 100vw;display: grid;place-items: center;
}
.calculator{position: relative;height: auto;width: auto;padding: 20px;border-radius: 10px;box-shadow: 0 0 30px #000;
}
#display{margin: 0 10px;height: 150px;width: auto;max-width: 270px;display: flex;align-items: flex-end;justify-content: flex-end;font-size: 30px;overflow-x: scroll;
}
#display::-webkit-scrollbar{display: block;height: 3px;
}
button{height: 60px;width: 60px;border: 0;border-radius: 30px;margin: 5px;font-size: 20px;cursor: pointer;transition: all 200ms ease;
}
button:hover{transform: scale(1.1);
}
button#equal{height: 130px;
}.calculator{background-color: #fff;
}
.calculator #display{color: #0a1e23;
}
.calculator button#clear{background-color: #ffd5d8;color: #fc4552;
}
.calculator button.btn-number{background-color: #c3eaff;color: #000;
}
.calculator button.btn-operator{background-color: #7ed0b0;color: #f39408;
}
.calculator button.btn-equal{background-color: #adf9e7;color: #000;
}

以上是css部分的代码,主要对界面的颜色样式进行了美化。

const display = document.querySelector('#display');
const buttons = document.querySelectorAll('button');const submit = function () {let subdata = null;// 定义表单对象const data = {}// 获取input框内内容const displayData = display.innerTextdata.display = displayDataconsole.log(data);const req = fetch('http://localhost:8081/cal/c', {body: JSON.stringify(data),method: "POST",headers: {'Content-Type': 'application/json'}})req.then(res => res.text()).then(res => {subdata = JSON.parse(res);if (!subdata.status)display.innerText = '输入格式错误'else {console.log(subdata);display.innerText = subdata.result}}).catch(err => {console.log(err)})
}buttons.forEach((item) => {item.onclick = () => {if (item.id == 'clear') {display.innerText = '';} else if (item.id == 'backspace') {let string = display.innerText.toString();display.innerText = string.substr(0, string.length - 1);} else if (display.innerText != '' && item.id == 'equal') {submit()} else if (display.innerText == '' && item.id == 'equal') {display.innerText = 'Empty!';setTimeout(() => (display.innerText = ''), 2000);} else {display.innerText += item.id;}}
})
const calculator = document.querySelector('.calculator');

以上是JavaScript部分的代码,主要负责按钮的点击事件、给后端发送请求以及对后端返回结果的处理。

2.后端部分

@RestController
@RequestMapping("/cal")
public class Controller {@Autowiredprivate ServiceImpl service;@PostMapping("/c")public Res calcula(@RequestBody data data) {return service.calculate(data.getDisplay());}
}@Service
public class ServiceImpl {public Res calculate(String text) {return new Res(Calculator.isValidExpression(text) ? Calculator.calculateExpression(text) : null,Calculator.isValidExpression(text) ? 1 : 0);}
}

以上是后端给出的请求接口以及业务逻辑层的方法。

@Data
@AllArgsConstructor
public class Res {public Integer result;public int status;
}public class data {private String display;public data() {}public String getDisplay() {return display;}public void setDisplay(String display) {this.display = display;}public data(String display) {this.display = display;}@Overridepublic String toString() {return "data{" +"display='" + display + '\'' +'}';}
}

以上是给前端返回结果的包装类以及接收前端数据的实体类。

public class Calculator {public static int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1;}}public static boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}public static int cal(int num1, int num2, int oper) {int res = 0;switch (oper) {case '+':res = num1 + num2;break;case '-':res = num2 - num1;break;case '*':res = num1 * num2;break;case '/':res = num2 / num1;break;}return res;}public static int calculateExpression(String expression) {Stack<Integer> numStack = new Stack<>();Stack<Character> operStack = new Stack<>();int index = 0;int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' ';String keepNum = "";while (true) {ch = expression.substring(index, index + 1).charAt(0);if (isOper(ch)) {if (!operStack.isEmpty()) {if (priority(ch) <= priority(operStack.peek())) {num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = cal(num1, num2, oper);numStack.push(res);operStack.push(ch);} else {operStack.push(ch);}} else {operStack.push(ch);}} else if (ch == '(') {int endIndex = getEndBracketIndex(expression, index);String subExpression = expression.substring(index + 1, endIndex);int subRes = calculateExpression(subExpression);numStack.push(subRes);index = endIndex;} else {keepNum += ch;if (index == expression.length() - 1) {numStack.push(Integer.parseInt(keepNum));keepNum = "";} else {if (isOper(expression.substring(index + 1, index + 2).charAt(0))) {numStack.push(Integer.parseInt(keepNum));keepNum = "";}}}index++;if (index >= expression.length()) {break;}}while (!operStack.isEmpty()) {num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop();res = cal(num1, num2, oper);numStack.push(res);}return numStack.pop();}private static int getEndBracketIndex(String expression, int startIndex) {Stack<Integer> stack = new Stack<>();for (int i = startIndex; i < expression.length(); i++) {char ch = expression.charAt(i);if (ch == '(') {stack.push(i);} else if (ch == ')') {stack.pop();if (stack.isEmpty()) {return i;}}}return 0;}public static boolean isValidExpression(String expr) {// 去除空格expr = expr.replaceAll("\\s", "");// 使用栈保存左括号Stack<Character> stack = new Stack<>();for (int i = 0; i < expr.length(); i++) {char c = expr.charAt(i);if (isLeftParenthesis(c)) {stack.push(c);} else if (isRightParenthesis(c)) {if (stack.isEmpty()) {return false;} else {stack.pop();}} else if (isOperator(c)) {if (i == 0 || i == expr.length() - 1 || isOperator(expr.charAt(i - 1)) || isOperator(expr.charAt(i + 1))) {return false;}if (c == '/' && (i == expr.length() - 2 || expr.charAt(i + 2) == '0')) {return false;}} else if (!Character.isDigit(c)) {return false;}}return stack.isEmpty();}public static boolean isLeftParenthesis(char c) {return c == '(';}public static boolean isRightParenthesis(char c) {return c == ')';}public static boolean isOperator(char c) {return c == '+' || c == '-' || c == '*' || c == '/';}
}

以上是对表达式进行处理并计算结果的一个简单的计算器类,该类提供了以下几个方法:

  • priority(int oper):根据运算符的优先级,返回一个整数值,其中乘法和除法的优先级为1,加法和减法的优先级为0,其他情况返回-1。
  • isOper(char val):判断给定字符是否为运算符(+、-、*、/)。
  • cal(int num1, int num2, int oper):根据给定的两个数字和一个运算符,进行相应的计算并返回结果。运算符对应的计算包括加法、减法、乘法和除法。
  • calculateExpression(String expression):通过指定的数学表达式进行计算,并返回计算结果。该方法使用两个栈来实现计算过程。一个栈用于存储数字,另一个栈用于存储运算符。遍历表达式的字符,根据字符的类型进行相应的操作。如果是运算符,则根据运算符的优先级决定是否进行计算;如果是左括号,则寻找对应的右括号,并将括号内的子表达式进行递归计算;如果是数字,则将数字压入数字栈中。最后,将剩余的运算符依次进行计算,直到栈为空,返回最终的计算结果。
  • getEndBracketIndex(String expression, int startIndex):辅助方法,用于获取给定表达式中与指定左括号对应的右括号的位置。
  • isValidExpression(String expr):判断给定的表达式是否为有效的数学表达式。方法首先去除字符串中的空格,然后使用栈来检查表达式中的括号是否匹配以及运算符的使用是否正确。具体规则如下:左括号入栈,遇到右括号出栈,如果栈为空则表示括号不匹配;如果遇到运算符,则判断其前后是否有运算符,以及除法运算符是否除以0,如果不符合规则则表达式无效;如果遇到非数字和非运算符的字符,则表达式无效。最后,如果栈为空,则表示括号匹配,返回true,否则返回false。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/175977.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【小白的Spring源码手册】 Bean的扫描、装配和注册,面试学习可用

目录 前言源码学习Bean配置1. 注解2. xml配置 Bean扫描、装配、注册1. 扫描2. 装配BeanDefinition3. 校验BeanDefinition4. 注册BeanDefinition 总结 前言 如今Spring框架功能众多&#xff0c;每次打开Spring源码&#xff0c;要么就是自顶向下从整个框架来了解Spring整体流程&…

Servlet 初始化参数(web.xml和@WebServlet)

1、通过web.xml方式 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://xmlns.jcp.org/xm…

SpringMVC学习

一、SpringMvc 概述 1.什么是SpringMVC? ( •̀ ω •́ )✧&#xff1a; SpringMVC是基于MVC开发模式的框架&#xff0c;具备IOC和AOP MyBatis用来优化持久层&#xff0c; SpringMVC优化控制器。 spring是用来整合这两个框架 的框架

Maven项目管理

文章目录 Maven项目管理项目结构依赖导入依赖依赖作用域可选依赖排除依赖 继承关系常用命令测试项目打包项目 Maven项目管理 Maven 翻译为"专家"、“内行”&#xff0c;是 Apache 下的一个纯 Java 开发的开源项目。 基于项目对象模型&#xff08;缩写&#xff1a;P…

『OpenStack』云计算平台『Nova』计算服务学习指南

前言 本文将会讲解 OpenStack 平台计算服务组件 Nova &#xff0c;结合抽象概念和简单易懂的实战操作&#xff0c;帮助您更好的理解 Nova 计算服务在 OpenStack 中的作用 系统配置&#xff1a;宿主机 Ubuntu 20.04&#xff08;WSL2&#xff09; 简介 OpenStack 官网链接&…

KnowledgeGPT:利用检索和存储访问知识库上增强大型语言模型10.30

利用检索和存储访问知识库上增强大型语言模型 摘要引言2 相关研究3方法3.1 任务定义3.2 知识检索3.2.1 代码实现3.2.2 实体链接3.2.3 获取实体信息3.2.4 查找实体或值3.2.5 查找关系 3.3 知识存储 4 实验 摘要 大型语言模型&#xff08;LLM&#xff09;在自然语言处理领域展现…

基于供需算法的无人机航迹规划-附代码

基于供需算法的无人机航迹规划 文章目录 基于供需算法的无人机航迹规划1.供需搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用供需算法来优化无人机航迹规划。 1.供需搜索算法 …

2024年湖北黄冈建安ABC建筑企业专职安全员报名事项

2024年湖北黄冈建安ABC建筑企业专职安全员报名事项 专职安全员一般是指从事安全管理方面的工作&#xff0c;普遍的是建筑施工行业&#xff0c;建筑工地安全员&#xff0c;专职安全员C证&#xff0c;黄冈建筑安全员ABC-建筑单位在黄冈&#xff0c;只能在黄冈报考建筑安全员ABC。…

前端基础---跳转相关的功能

后端给链接地址并且给token进行跳转 如果点击有key4&#xff0c;说明要跳转到相应的页面 auth是通过后端获取的地址&#xff0c; jdk是后端获取的相应的token&#xff0c; 然后进行拼接&#xff0c;进行window.open&#xff08;&#xff09;进行跳转 if (key 4) {var testUrl …

Py之transformers_stream_generator:transformers_stream_generator的简介、安装、使用方法之详细攻略

Py之transformers_stream_generator&#xff1a;transformers_stream_generator的简介、安装、使用方法之详细攻略 目录 transformers_stream_generator的简介 1、Web Demo T1、original T2、stream transformers_stream_generator的安装 transformers_stream_generator的…

工会排队营销玩法,让消费者乐于参与其中

小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 工会…

HZGO-A-031/315、KZGO-A-031/50比例减压阀放大器

RZGO-A-010/210、RZGO-A-010/32、RZGO-A-010/100、RZGE-A-010/210、RZGE-A-010/32、RZGE-A-010/100、CART RZGE-A-010/210、CART RZGE-A-010/32、CART RZGE-A-010/100、RZGO-A-031/210、RZGO-A-033/100、HZGO-A-033/350、HZGO-A-031/315、KZGO-A-031/50、KZGO-A-033/210滑阀型、…

比Nginx测试桩更方便,ShenYu网关的Mock插件

有时候为了方便测试&#xff0c;我们需要模拟 HTTP 外部接口的返回结果。通常情况下&#xff0c;我们可以使用 Nginx 测试桩来实现这个目的。然而&#xff0c;Nginx 的使用门槛较高&#xff0c;可能对一些初级开发和测试人员来说有一定的难度。相比之下&#xff0c;Apache Shen…

使用传感器融合的前方碰撞预警-(Forward Collision Warning Using Sensor Fusion)

这个例子matlab自动驾驶工具箱中关于使用传感器融合的前方碰撞预警-(Forward Collision Warning Using Sensor Fusion)例子&#xff0c;其展示了如何通过融合视觉和雷达传感器的数据来跟踪车辆前方的物体&#xff0c;从而实现前向碰撞预警系统的开发与验证。 1 概述 前方碰撞…

JVM相关面试题(每日一练)

1. 什么是垃圾回收机制&#xff1f; 垃圾收集 Garbage Collection 通常被称为“GC”&#xff0c;它诞生于1960年 MIT 的 Lisp 语言&#xff0c;经过半个多世纪&#xff0c;目前已经十分成熟了。 jvm 中&#xff0c;程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭&a…

UML—时序图是什么

目录 前言: 什么是时序图: 时序图的组成元素&#xff1a; 1. 角色(Actor) 2. 对象(Object) 3. 生命线(LifeLine) 4. 激活期(Activation) 5. 消息类型(Message) 6.组合片段(Combined fragment) 时序图的绘制规则:​ 绘制时序图的3步&#xff1a; 1.划清边界&#xf…

mysql之用户管理、权限管理、密码管理

用户管理 创建用户create user 杨20.0.0.13 identified by 123; 用户重命名rename user 杨20.0.0.13 to yang20.0.0.13; 删除用户drop user 杨20.0.0.13; 权限管理 查看用户权限show grants for 杨20.0.0.13; 赋予用户权限grant all privileges on *.* to 杨localhost id…

【Spring Boot 源码学习】RedisAutoConfiguration 详解

Spring Boot 源码学习系列 RedisAutoConfiguration 详解 引言往期内容主要内容1. Spring Data Redis2. RedisAutoConfiguration2.1 加载自动配置组件2.2 过滤自动配置组件2.2.1 涉及注解2.2.2 redisTemplate 方法2.2.3 stringRedisTemplate 方法 总结 引言 上篇博文&#xff0…

微信小程序开发-微信支付退款功能【附有完整代码】

之前有写过详细的微信支付功能&#xff1a;微信支付 我们使用weixin-java-pay的jar包等&#xff0c;配置上的流程同微信支付&#xff0c;可以看上面的文章。 退款使用的WxPayService类的refundV3方法。使用该方法需要在微信支付配置的基础上加上&#xff1a;apiclient_key.pem…

Nginx 部署多个安全域名,多个服务【工作记录】

以下是本人通过Docker 部署的Nginx挂载出来的文件目录 先看下 nginx.conf 配置文件内容&#xff1a;如下 ps&#xff1a;当前文件就是安装后的初始内容&#xff0c;无修改。主要关注最后一行 include /etc/nginx/conf.d/*.conf;表示引入其他目录下的.conf配置文件&#xff1b;…