200行Java代码搞定计算器程序
发现了大学时候写的计算器小程序,还有个图形界面,能够图形化展示表达式语法树,哈哈;)
只有200行Java代码,不但能够计算加减乘除,还能够匹配小括号~
代码点评:
从朴素的界面配色到简单易懂错误提示,无不体现了“用户体验”至上的设计理念;代码异常处理全面合理、滴水不漏,代码缩进优雅大方,变量命名直观易懂;再结合长度适中简单明了的注释,程序整体给人一种清新脱俗之感。背后不难看出作者对学习的热爱以及对设计的苛求,工匠精神可见一斑,真可谓是大学数据结构学以致用的典范!
关于数据结构的干货,可参考博主的《深入理解Java集合框架》系列文章,一定不让你失望。
实现算法参考严蔚敏的《数据结构(C语言版)》第三章“栈和队列”,3.2.5节“表达式求值”。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.TextField;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Stack;
import javax.swing.JFrame;
/**
* 图形界面的计算器程序,只能计算加减乘除,
* 算式中可以有小括号。数字可以是小数
*/
public class CalcGUI extends JFrame{
private static final long serialVersionUID = 1L;
private TreeNode resultTree;
private String textFieldString;
private boolean calcSuccess = true;
private char ops[][] = {
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'<', '<', '<', '<', '<', '=', 'E'},
{'E', 'E', 'E', 'E', 'E', 'E', 'E'},
{'<', '<', '<', '<', '<', 'E', '='},
};
Stack<TreeNode> nodesStack = new Stack<TreeNode>();
Stack<Character> opsStack = new Stack<Character>();
public static void main(String[] args) {
CalcGUI gui = new CalcGUI();
gui.userGUI();
}
public void userGUI(){
this.setLayout(new BorderLayout());
TextField tf = new TextField("请输入表达式,按Enter开始计算~", 40);
tf.selectAll();
tf.getText();
tf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
textFieldString = ((TextField)e.getComponent()).getText();
calcSuccess = true;
resultTree = null;
try{
resultTree = calc(textFieldString + "#");
}catch(Exception e1){
calcSuccess = false;
}
CalcGUI.this.repaint();
}
}
});
this.add(tf, BorderLayout.NORTH);
this.setSize(500, 500);
this.setTitle("calc GUI");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(true);
this.setVisible(true);
}
private int levelHeight = 60;
private int diameter = 25;
public void paint(Graphics g){
super.paint(g);
if(calcSuccess){
if(resultTree != null){
g.drawString("计算结果为:" + resultTree.value, 10, 80);
int rootBeginX = this.getWidth() / 2;
int rootBeginY = 100;
Point p = new Point(rootBeginX, rootBeginY);
drawTree(g, resultTree, p, this.getWidth() / 2 - 20, p);
}
}else{
g.setColor(Color.RED);
g.drawString("表达式语法有误!", 10, 80);
}
}
private void drawCircle(Graphics g, Point p, int r){
g.drawOval(p.x - r, p.y - r, r * 2, r * 2);
}
private void drawTree(Graphics g, TreeNode node, Point pme, int width, Point pfather){
if(node == null) return;
// System.out.println("in drawTree, node.value=" + node.value + ",node.op=" + node.op);
g.setColor(Color.GREEN);
this.drawCircle(g, pme, diameter / 2);
g.drawLine(pme.x, pme.y, pfather.x, pfather.y);
if(node.op != 'E'){
g.setColor(Color.BLACK);
g.drawString(String.valueOf(node.op), pme.x, pme.y);
}else{
g.setColor(Color.BLACK);
g.drawString(String.valueOf(node.value), pme.x - diameter / 2, pme.y);
}
drawTree(g, node.lft, new Point(pme.x - width / 2, pme.y + levelHeight), width / 2, pme);
drawTree(g, node.rt, new Point(pme.x + width / 2, pme.y + levelHeight), width / 2, pme);
}
public TreeNode calc(String inStr) throws Exception{
opsStack.push('#');
StringBuilder buf = new StringBuilder();
int i = 0;
while(i < inStr.length()){
if(Character.isDigit(inStr.charAt(i)) || inStr.charAt(i) == '.'){// number
buf.delete(0, buf.length());
while(i < inStr.length() &&
(Character.isDigit(inStr.charAt(i)) || inStr.charAt(i) == '.'))
buf.append(inStr.charAt(i++));
Double number = Double.parseDouble(buf.toString());
nodesStack.push(new TreeNode(number));
}else if(inStr.charAt(i) == ' '){
i++;
continue;
}else{// operation
char op = inStr.charAt(i);
int subNew = getSub(op);
boolean goOn = true;
while(goOn){
if(opsStack.isEmpty())
throw new Exception("运算符太少!");
char opFormer = opsStack.peek();
int subFormer = getSub(opFormer);
switch(ops[subFormer][subNew]){
case '=':
goOn = false;
opsStack.pop();
break;
case '<':
goOn = false;
opsStack.push(op);
break;
case '>':
goOn = true;
TreeNode n1 = nodesStack.pop();
TreeNode n0 = nodesStack.pop();
double rs = doOperate(n0.value, n1.value, opFormer);
nodesStack.push(new TreeNode(rs, opFormer, n0, n1));
opsStack.pop();
break;
default:
throw new Exception("没有匹配的操作符:" + op);
}
}
i++;
}
}
return nodesStack.pop();
}
private double doOperate(double n0, double n1, char op) throws Exception{
switch(op){
case '+': return n0 + n1;
case '-': return n0 - n1;
case '*': return n0 * n1;
case '/': return n0 / n1;
default: throw new Exception("非法操作符:" + op);
}
}
private int getSub(char c){
switch(c){
case '+': return 0;
case '-': return 1;
case '*': return 2;
case '/': return 3;
case '(': return 4;
case ')': return 5;
case '#': return 6;
default : return -1;
}
}
}
class TreeNode{
public double value;
public char op = 'E';
public TreeNode lft;
public TreeNode rt;
public TreeNode(double value){
this.value = value;
}
public TreeNode(double value, char op, TreeNode lft, TreeNode rt){
this.value = value;
this.op = op;
this.lft = lft;
this.rt = rt;
}
StringBuilder buf = new StringBuilder();
public String toString(){
out(this);
return buf.toString();
}
private void out(TreeNode node){
if(node == null) return;
out(node.lft);
if(node.op != 'E')
buf.append(node.op);
else
buf.append(node.value);
out(node.rt);
}
}
200行Java代码搞定计算器程序的更多相关文章
- 5行js代码搞定导航吸顶效果
一.HTML布局 首先写HTML布局 <body> <div id="wrap"></div> </body> 二.CSS样式 给点 ...
- 180行ruby代码搞定游戏2048
最今在玩2048这款小游戏,游戏逻辑简单,很适合我这样的对于游戏新入行的人来实现逻辑.于是选择了最拿手的ruby语言来实现这款小游戏的主要逻辑.还是挺简单的,加起来4小时左右搞定. 上代码: requ ...
- 【备忘】windows环境下20行php代码搞定音频裁剪
先上图,由于最近的需求需要对语音文件进行处理,所以抽空研究了下php处理音/视频文件的处理,简单的demo处理,截取一个音频文件的前20秒,并保存新的媒体文件. 操作步骤: ①在此站点下载所需的辅助程 ...
- 80行Python代码搞定全国区划代码
微信搜索:码农StayUp 主页地址:https://gozhuyinglong.github.io 源码分享:https://github.com/gozhuyinglong/blog-demos ...
- 几行JavaScript代码搞定Iframe 自动适应
场景:Iframe嵌入flash,希望flash能随着页面的resize而resize. 主要代码: 代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTM ...
- 几句java代码搞定十万个为什么数据
最近想做一个app,为小朋友推荐十万个为什么的故事,但是找了很久数据,发现挺难的找的,又去写爬虫,发现没有一个好的网站可以爬,最后一个偶然的机会在csdn上发现一个可用的接口,很快就把问题解决了,下面 ...
- 3kb jQuery代码搞定各种树形选择。
自制Jquery树形选择插件. 对付各种树形选择(省市,分类..)90行Jquery代码搞定,少说废话直接上插件代码.稍后介绍使用说明.是之前写的一个插件的精简版. 1.Jquery插件代码 /* * ...
- 30行代码搞定WCF并发性能测试
[以下只是个人观点,欢迎交流] 30行代码搞定WCF并发性能 轻量级测试. 1. 调用并发测试接口 static void Main() { List< ...
- 10行代码搞定移动web端自定义tap事件
发发牢骚 移动web端里摸爬滚打这么久踩了不少坑,有一定移动web端经验的同学一定被click困扰过.我也不列外.一路走来被虐的不行,fastclick.touchend.iscroll什么的都用过, ...
随机推荐
- linux C 文件操作之fgets()
1. fgets(...)从标准设备读数据. 原型:fgets(s,n,stdin); 假设在控制台下,我们可以用fgets(...)替代gets(),读入键盘输入的信息,fget ...
- 伤不起的微信小程序
前段时间不是很忙,刚好公司需要开发一个微信小程序,于是我就入坑了(此坑还是有点深滴,请备好干粮). 我是一名iOS开发工程师,个人觉得入门开发小程序的话,需要基本的web前端知识,比如说:代码的书写格 ...
- hbase的HQuorumPeer和QuorumPeerMain
hbase是列式数据库,既可以单机也可以以集群的方式搭建,以集群的方式搭建一般建立在hdfs之上. 分布式的hbase如何启动? 首先启动hadoop,然后就来问题了:zookeeper和hbase的 ...
- 淘宝轮播JS
taobao首页轮播原生js面对对象封装版 Author:wyf 2012/2/25
- SQL系统函数的使用(实验五)
SQL系统函数的使用(试验5) 函数在查询语句中的使用 查询员工的姓名和日工资(保留1位小数): 查询并显示部门号为01和02的所有员工的姓名首字及岗位: 查询并显示所有员工的姓名及工龄: 查询199 ...
- canvas画布实现手写签名效果
最近项目中涉及到移动端手写签名的功能需求,将实现代码记录于此,供小伙伴们参考指摘哦~ HTML代码: <!--手写区--> <div class="mSign_signMa ...
- word,excel,ppt转Pdf,Pdf转Swf,通过flexpaper+swftools实现在线预览
其实这是我好几年前的项目,现在再用这种方式我也不建议了,毕竟未来flash慢慢会淘汰,此方式也是因为目测大部分人都装了flash,才这么做的,但是页面展示效果也不好.其实还是考虑收费的控件,毕竟收费的 ...
- php中向前台js中传送一个二维数组
在php中向前台js中传送一个二维数组,并在前台js接收获取其中值的全过程方法: (1),方法说明:现在后台将数组发送到前台 echo json_encode($result); 然后再在js页面中的 ...
- 解决thymeleaf layout布局不生效
今天使用thymeleaf layout布局时总是不生效,特此把解决问题的步骤和几个关键点记录下来备忘. 一.检查依赖 1.thymeleaf必备maven依赖: <dependency> ...
- 以太坊客户端Geth命令用法-参数详解
Geth在以太坊智能合约开发中最常用的工具(必备开发工具),一个多用途的命令行工具. 熟悉Geth可以让我们有更好的效率,大家可收藏起来作为Geth命令用法手册. 本文主要是对geth help的翻译 ...