(點選上方公眾號,可快速關註)
來源:CarpenterLee,
www.cnblogs.com/CarpenterLee/p/8045117.html
發現了大學時候寫的計算器小程式,還有個圖形介面,能夠圖形化展示運算式語法樹。
只有200行Java程式碼,不但能夠計算加減乘除,還能夠匹配小括號~
程式碼點評:
從樸素的介面配色到簡單易懂錯誤提示,無不體現了“使用者體驗”至上的設計理念;程式碼異常處理全面合理、滴水不漏,程式碼縮排優雅大方,變數命名直觀易懂;再結合長度適中簡單明瞭的註釋,程式整體給人一種清新脫俗之感。背後不難看出作者對學習的熱愛以及對設計的苛求,工匠精神可見一斑,真可謂是大學資料結構學以致用的典範!
關於資料結構的乾貨,可參考博主的《深入理解Java集合框架》系列文章,一定不讓你失望。
http://www.cnblogs.com/CarpenterLee/p/5545987.html
實現演演算法參考嚴蔚敏的《資料結構(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’},
{‘
};
Stack
nodesStack = new Stack (); Stack
opsStack = new Stack (); 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);
}
}
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能