发现了大学时候写的计算器小程序,还有个图形界面,能够图形化展示表达式语法树,哈哈;)

只有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代码搞定计算器程序的更多相关文章

  1. 5行js代码搞定导航吸顶效果

    一.HTML布局 首先写HTML布局 <body> <div id="wrap"></div> </body> 二.CSS样式 给点 ...

  2. 180行ruby代码搞定游戏2048

    最今在玩2048这款小游戏,游戏逻辑简单,很适合我这样的对于游戏新入行的人来实现逻辑.于是选择了最拿手的ruby语言来实现这款小游戏的主要逻辑.还是挺简单的,加起来4小时左右搞定. 上代码: requ ...

  3. 【备忘】windows环境下20行php代码搞定音频裁剪

    先上图,由于最近的需求需要对语音文件进行处理,所以抽空研究了下php处理音/视频文件的处理,简单的demo处理,截取一个音频文件的前20秒,并保存新的媒体文件. 操作步骤: ①在此站点下载所需的辅助程 ...

  4. 80行Python代码搞定全国区划代码

    微信搜索:码农StayUp 主页地址:https://gozhuyinglong.github.io 源码分享:https://github.com/gozhuyinglong/blog-demos ...

  5. 几行JavaScript代码搞定Iframe 自动适应

    场景:Iframe嵌入flash,希望flash能随着页面的resize而resize. 主要代码: 代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTM ...

  6. 几句java代码搞定十万个为什么数据

    最近想做一个app,为小朋友推荐十万个为什么的故事,但是找了很久数据,发现挺难的找的,又去写爬虫,发现没有一个好的网站可以爬,最后一个偶然的机会在csdn上发现一个可用的接口,很快就把问题解决了,下面 ...

  7. 3kb jQuery代码搞定各种树形选择。

    自制Jquery树形选择插件. 对付各种树形选择(省市,分类..)90行Jquery代码搞定,少说废话直接上插件代码.稍后介绍使用说明.是之前写的一个插件的精简版. 1.Jquery插件代码 /* * ...

  8. 30行代码搞定WCF并发性能测试

    [以下只是个人观点,欢迎交流] 30行代码搞定WCF并发性能 轻量级测试. 1. 调用并发测试接口 static void Main()         {               List< ...

  9. 10行代码搞定移动web端自定义tap事件

    发发牢骚 移动web端里摸爬滚打这么久踩了不少坑,有一定移动web端经验的同学一定被click困扰过.我也不列外.一路走来被虐的不行,fastclick.touchend.iscroll什么的都用过, ...

随机推荐

  1. Milking Time

    Description Bessie is such a hard-working cow. In fact, she is so focused on maximizing her producti ...

  2. 实现基于lnmp的电子商务网站

    今天带给大家的是一个实战项目,主要是让大家了解在我们接到一个项目时,我们该怎样做好这个项目,下面看具体内容: 技术说明 LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器 ...

  3. caffe源码分析 vector<Blob<Dtype>*>& bottom

    Blob:4个维度 n x c x h x w: bottom[0] .bottom[1]代表该层有几个输入. bottom[0]->count(): 输入中,元素的总维数(个数) bottom ...

  4. 1.Introduction 介绍

    Welcome to Log4j 2! Introduction Almost every large application includes its own logging or tracing ...

  5. Problem D: 栈小游戏

    #include <iostream> #include <vector> #include <stack> #include <algorithm> ...

  6. Apache降权和禁用PHP危险函数

    测试环境: Windows Server 2003 + phpstudy 首先在win2003里运行phpstudy,这里注意需要选择应用系统服务模式,应用之后重启phpstudy. 打开系统服务(开 ...

  7. ldap数据库--ODSEE--suffix

    ldap数据库的suffix是建立ldap之间复制协议的基础,suffix的创建也可以通过管理界面进行,也可以通过命令行进行.不同点是通过管理界面创建的suffix会自动创建一条对应该suffix的匿 ...

  8. 入门到熟练-SpringBoot

    Spring Boot概述 1.1. Spring Boot是什么 Spring Boot是一套基于Spring框架的微服务框架. 1.2. Spring Boot框架出现的背景 由于Spring是一 ...

  9. C++雾中风景1:友元类与面向对象

    因为后续准备入职的公司都希望能转C++,所以最近也是按部就班的开始进行C++的学习.然后这个系列的文章打算探究C++的语言特性,也比较一下不同语言(如Java,Scala,Python,Go)之间的设 ...

  10. JVM命令

    jstack--jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息: jinfo--jinfo可以输出并修改运行时的java 进程的opts.用处比较简单 ...