用Java写一个简单的计算器程序
主要思路
中缀表达式转后缀表达式,后缀表达式求值
代码部分
1.因为转换表达式需要用到栈,所以先定义一个类,进行栈的相关操作:
public class Clip {
private int maxSize;
private char[] clip;
private int top;
private boolean flag;
public int getMaxSize() {
return maxSize;
}
public char[] getClip() {
return clip;
}
public int getTop() {
return top;
}
public boolean isFlag() {
return flag;
}
@Override
public String toString() {
return "Clip{" +
"clip=" + Arrays.toString(clip) +
", top=" + top +
'}';
}
public Clip() {
init(100);
}
public void setFlag(boolean flag) {
this.flag = flag;
}
//初始化
public void init(int max){
maxSize = max;
clip = new char[maxSize];
top = -1;
flag = true;
}
//入栈操作
public void push(char p){
clip[++top] = p;
}
//出栈操作
public char pop(){
return clip[top--];
}
//返回当前栈顶元素
public char peekThisTop(){
return clip[top];
}
//判断当前栈的状态(空或非空)
public boolean isEmpty(){
return (top == -1);
}
}2.接下来我们写一个类,这个类中定义了计算过程中所需要的所有操作:
public class Count {
//该方法最终会将输入的待计算式子转化为后缀表达式存储在clip_1对象中并将其返回
public Clip pushCount(String pushCount){
Clip clip_1 = new Clip();
Clip clip_2 = new Clip();
char[] chars = pushCount.toCharArray();
if (!checkoutBracket(chars)) {
clip_1.setFlag(false);
return clip_1;
}else {
for (char a : chars) {
switch (a) {
case '(':
//如果扫描过程中遇到‘(’,直接入clip_1即可
clip_2.push(a);
break;
//如果遇到‘)’,判断此时的栈顶元素是否为操作符,是,直接弹出
case ')':
topIsBracket(clip_2);
clip_1.push(clip_2.pop());
topIsBracket(clip_2);
break;
//如果遇到操作符调用isOperator()对其进行进一步操作
case '+':
case '-':
case 'x':
case '/':
//处理入栈;
isOperator(clip_1, clip_2, a);
break;
default:
//数字和小数点直接入clip_1
clip_1.push(a);
}
}
while (clip_2.getTop() != -1) {
char pop = clip_2.pop();
if (pop != '(') clip_1.push(pop);
}
clip_1.push('#');
return clip_1;
}
}
public void isOperator(Clip clip_1,Clip clip_2,char a){
//如果传入操作符的优先级大于此时clip_2的栈顶元素
if (clip_2.getTop() == -1||clip_2.peekThisTop() == '(' || priority(a) > priority(clip_2.peekThisTop())){
clip_1.push('_');
clip_2.push(a);
}else {
//如果传入操作符的优先级小于此时clip_2的栈顶元素
clip_1.push(clip_2.pop());
clip_2.push(a);
}
}
//设置并返回传入操作符的优先级
public int priority(char a){
int i = 0;
switch (a){
case '+':
case '-':
break;
case 'x':
case '/':
i = 1;
}
return i;
}
//如果clip此时的栈顶元素是‘(’,该方法会将其直接弹出
public void topIsBracket(Clip clip){
if (clip.peekThisTop() == '(') clip.pop();
}
//该方法用于对转换得到的后缀表达式求值
public List<String> countFormula(Clip clip){
double sum = 0.0;
List<String> classify = classify(clip.getClip());
for(int i = 0;i < classify.size();i++){
switch (bracketIndex(classify.get(i).charAt(0))){
case 0:
sum = Double.parseDouble(classify.get(i-2)) + Double.parseDouble(classify.get(i-1));
classify.remove(i-2);
classify.remove(i-2);
classify.remove(i-2);
classify.add(i-2,String.valueOf(sum));
i = 0;
break;
case 1:
sum = Double.parseDouble(classify.get(i-2)) - Double.parseDouble(classify.get(i-1));
classify.remove(i-2);
classify.remove(i-2);
classify.remove(i-2);
classify.add(i-2,String.valueOf(sum));
i = 0;
break;
case 2:
sum = Double.parseDouble(classify.get(i-2)) * Double.parseDouble(classify.get(i-1));
classify.remove(i-2);
classify.remove(i-2);
classify.remove(i-2);
classify.add(i-2,String.valueOf(sum));
i = 0;
break;
case 3:
sum = Double.parseDouble(classify.get(i-2)) / Double.parseDouble(classify.get(i-1));
/*
* 格式化计算结果
*/
DecimalFormat decimalFormat = new DecimalFormat("0.0000000");
String format = decimalFormat.format(sum);
classify.remove(i-2);
classify.remove(i-2);
classify.remove(i-2);
classify.add(i-2,format);
i = 0;
break;
}
}
return classify;
}
/*试想一下如果我们要计算123x4
* 1.经过前面的操作后式子变成这样char c[] = {'1','2','3','4','x'}
* 2.经过该方法的处理它会变成这样["123","4","x"]
*/
public List<String> classify(char c[]){
List<String> list = new ArrayList<String>();
String out = "";
for (char a : c){
if (a == '#') break;
if (judgeIsBracket(a)) {
if (out != "")list.add(out);
list.add(String.valueOf(a));
out = "";
}
else if(a == '_') {
list.add(out);
out = "";
}
else out = out + a;
}
return list;
}
//判断传入的字符是否为操作符
public boolean judgeIsBracket(char a){
switch (a){
case '+':
case '-':
case 'x':
case '/':
return true;
default:return false;
}
}
//求值操作会根据该方法的返回值而知晓应该为当前的两个数字施加何种运算
public int bracketIndex(char a){
int i = 0;
switch (a){
case '+': i = 0;break;
case '-': i = 1;break;
case 'x': i = 2;break;
case '/': i = 3;break;
default: i = -1;
}
return i;
}
//该方法用于判断用户输入式子中的括号是否成对
public boolean checkoutBracket (char c[]){
int i = 0;
int j = 0;
for (char a : c){
if (a == '(') i++;
if (a == ')') j++;
}
boolean b = i == j ? true : false;
return b;
}
}3.定义一个测试类,用于之后检验各模块是否正常工作:
import org.junit.Test;
//注意:使用测试类的前提是需要导入对应依赖的jar包,如果该部分报错
// 方案一:直接删除这个类
// 方案二:导入对应jar包
public class test {
@Test
public void Test(){
//你的测试代码
}
}4.图形化界面:
public class CountView extends Thread implements ActionListener{
JFrame main;
JPanel centre;
JTextArea t01;
JButton bt0,bt1,bt2,bt3,bt4,bt5,bt6,bt7,bt8,bt9,bt_0,bt_1,bt_2,bt_3,bt_4,bt_5,bt_6,bt_7,bt_8;
public void run() {
main = new JFrame("一个计算器");
centre = new JPanel(new GridLayout(4,4));
bt0 = new JButton("0");
bt1 = new JButton("1");
bt2 = new JButton("2");
bt3 = new JButton("3");
bt4 = new JButton("4");
bt5 = new JButton("5");
bt6 = new JButton("6");
bt7 = new JButton("7");
bt8 = new JButton("8");
bt9 = new JButton("9");
bt_0 = new JButton("+");
bt_1 = new JButton("-");
bt_2 = new JButton("x");
bt_3 = new JButton("/");
bt_4 = new JButton("=");
bt_5 = new JButton(".");
bt_6 = new JButton("(");
bt_7 = new JButton(")");
bt_8 = new JButton("Reset");
t01 = new JTextArea(1,390);
bt0.addActionListener(this);
bt1.addActionListener(this);
bt2.addActionListener(this);
bt3.addActionListener(this);
bt4.addActionListener(this);
bt5.addActionListener(this);
bt6.addActionListener(this);
bt7.addActionListener(this);
bt8.addActionListener(this);
bt9.addActionListener(this);
bt_0.addActionListener(this);
bt_1.addActionListener(this);
bt_2.addActionListener(this);
bt_3.addActionListener(this);
bt_4.addActionListener(this);
bt_5.addActionListener(this);
bt_6.addActionListener(this);
bt_7.addActionListener(this);
bt_8.addActionListener(this);
main.setLayout(null);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setSize(400,300);
main.setLocationRelativeTo(null);
main.setResizable(false);
main.setVisible(true);
main.getContentPane().add(centre);
main.getContentPane().add(bt_6);
main.getContentPane().add(bt_7);
main.getContentPane().add(bt_8);
main.getContentPane().add(t01);
bt_6.setBounds(0,40,(main.getWidth()-10)/3,20);
bt_7.setBounds(130,40,(main.getWidth()-10)/3,20);
bt_8.setBounds(260,40,(main.getWidth()-10)/3,20);
centre.setBounds(0,60,main.getWidth()-10,main.getHeight()-100);
t01.setBackground(Color.BLACK);
t01.setForeground(Color.WHITE);
t01.setSize(main.getWidth()-10,40);
t01.setFont(new Font("宋体",Font.BOLD,18));
centre.add(bt7);
centre.add(bt8);
centre.add(bt9);
centre.add(bt_0);
centre.add(bt4);
centre.add(bt5);
centre.add(bt6);
centre.add(bt_1);
centre.add(bt1);
centre.add(bt2);
centre.add(bt3);
centre.add(bt_2);
centre.add(bt_3);
centre.add(bt0);
centre.add(bt_5);
centre.add(bt_4);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() != bt_4 && e.getSource() != bt_8){
fontStyle(t01,0);
strJoint(t01, (JButton) e.getSource());
}else if (e.getSource() == bt_8){
fontStyle(t01,-1);
}else {
if (checkoutBracket(t01)) getTextAndTransmit(t01);
}
}
public void strJoint(JTextArea jTextArea,JButton jButton){
jTextArea.append(jButton.getText().replace(" ",""));
}
public void getTextAndTransmit(JTextArea jTextArea){
String resu = "";
Count count = new Count();
Clip clip = count.pushCount(jTextArea.getText());
List<String> result = count.countFormula(clip);
for (String s : result){
resu += s;
}
fontStyle(t01,2);
jTextArea.setText(resu);
}
public boolean checkoutBracket(JTextArea jTextArea) {
Count count = new Count();
Clip clip = count.pushCount(jTextArea.getText());
if (!clip.isFlag()) {
fontStyle(t01,1);
return false;
} else return true;
}
//设置样式
public void fontStyle(JTextArea jTextArea, int i){
switch (i){
case -1:
jTextArea.setText("");
jTextArea.setForeground(Color.WHITE);
jTextArea.setFont(new Font("宋体",Font.BOLD,18));
break;
case 0:
jTextArea.setForeground(Color.WHITE);
jTextArea.setFont(new Font("宋体",Font.BOLD,18));
break;
case 1:
jTextArea.setForeground(Color.RED);
jTextArea.setText("公式可能存在括号不匹配错误!");
jTextArea.setFont(new Font("宋体",Font.BOLD,23));
break;
case 2:
jTextArea.setForeground(Color.GREEN);
jTextArea.setFont(new Font("宋体",Font.BOLD,23));
break;
}
}
}5.最后当然就是程序的入口了:
public class Entrance {
public static void main(String[] args) {
CountView countView = new CountView();
//主线程已满足该程序运行需求
countView.run();
}
}6.最终效果:


















