Java GUI实现的计算器(中缀转后缀,运算有顺序)
1、问题描述
本程序支持含负数、小数、多位数等多种操作数的处理,可以计算含加、减、乘、除、求余、求幂等多种运算符(“+”、“-”、“*”、“/”)的表达式,并能判断表达式括号是否匹配;从键盘输入一个正确的中缀表达式,将中缀表达式转换为计算机理解的后缀表达式,计算后缀表达式(运算有顺序)的值。
GUI计算器实现对于表达式中的简单错误,能够给出提示信息的弹窗,且不允许错误信息进入表达式;
(2)能够处理多种操作符
(3)实现包含简单运算的计算器
2、算法实现
中缀表达式转为后缀表达式
①我们使用一个stack栈结构存储操作符,用一个List结构存储后缀表达式结果,使用map结构来判断运算符的优先级;
②首先读取到数字,直接存入list中;
③当读取到左括号"("时,直接压栈,当读取到运算符时,分两种情况讨论;
-
运算符栈为空,直接入栈
-
当栈顶操作符的优先级 小于 当前运算符优先级时(如+和-的优先级低于 * 和 /),直接入栈;
-
当运算符不为空 且 栈顶操作符的优先级 大于或等于 当前运算符优先级时,循环执行出栈操作并加入list中,直到遇到优先级小于当前运算符的元素为止。循环执行完后再将当前运算符压栈。
PS. 只有遇到右括号时,左括号才出栈;
④当遇到右括号")"时,循环执行出栈操作并加入到list中,直到遇到左括号为止。并将左括号弹出,但不加入list中;
⑤表达式的值读取完后,将操作符栈中的所有元素弹出并加入到list中;
执行完上面步骤后,list中存储的顺序即为我们转换后的后缀表达式的结果
//中缀表达式转后缀表达式
public void evalRPN() {
Stack<String> stack = new Stack<>();
Iterator<String> iterator = expression.iterator();
while(iterator.hasNext()) {
String now = iterator.next();
System.out.println(now);
if(isNumeric(now)) {
suffix.add(now);//数字直接入list
}else{
if(stack.isEmpty()) {//判断栈是否为空
stack.add(now);
continue;
}
if(now.equals("(")) {//括号判断,分情况
stack.add(now);
}else if(now.equals(")")) {
while(true) {
if(stack.peek().equals("(")) {
stack.pop();
break;
}else{
suffix.add(stack.pop());
}
}
}else{
if(map.get(stack.peek()) < map.get(now) || (stack.peek()).equals("(")) {
stack.add(now);
}else{
while(true) {
suffix.add(stack.pop());
if(stack.isEmpty() == true ||map.get(stack.peek()) < map.get(now)) {
stack.add(now);
break;
}
}
}
}
}
}
suffix.add(stack.pop());
}
碎碎念:迭代器挺好用的
Iterator()方法
无论List、Set、Queue,都有个iterator()方法,定义在Collection接口中,而这些线性表和集合都是继承自Collection接口。iterator()方法会返回java.util.Iterator接口的操作对象(Collection收集的所有对象)。
static void forEach(Collection collection) {
//借forEach函数来展示迭代器方法
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
out.println(iterator.next());
}
}
常用方法
Iterator= list.iterator()
将集合list变成迭代器it,接下来就可以操作迭代器的方法了it.hasNext()
查看是否还有下一个元素it.next()
查看一个元素it.remove()
删除当前元素并返回
后缀表达式计算结果
将数字存入stack结构中,从右向左看,遇到运算符则使用stack.pop弹出最上面的两个数字,运算之后将结果压栈。持续往复,直到读取完表达式,此时栈内剩余的最后一个数值,即为后缀表达式的运算结果。
//后缀表达式计算结果
public void Calculate() {
Stack<Double> stack = new Stack<>();
for(int i = 0; i < suffix.size(); i++){
String item = suffix.get(i);
if(isNumeric(item)){
//是数字
stack.push(Double.parseDouble(item));
}else {
//是操作符,取出栈顶两个元素
Double num2 = stack.pop();
Double num1 = stack.pop();
Double res = 0.0;
if(item.equals("+")){
res = num1 + num2;
}else if(item.equals("-")){
res = num1 - num2;
}else if(item.equals("*")){
res = num1 * num2;
}else if(item.equals("/")){
res = num1 / num2;
}else if(item.equals("%")){
res = num1 % num2;
}else if(item.equals("^")){
res = Math.pow(num1,num2);
}
System.out.println(num1 + " " +num2+ " " + item + " " + res);
stack.push(res);
}
}
area.append("\n表达式结果为:"+stack.pop()+"\n");
}
3、GUI实现计算器
实图如下,有些尺寸大小可以按照自己的喜好改。
代码如下:
public class Calculator{
ArrayList<String> expression = new ArrayList<>();//存储每轮输入字符
String[] Operator = new String[]{"+","-","*","/","%","^","(",".",")"};//运算符集
public static HashMap<String,Integer> map = new HashMap<>();//运算符优先级
public static ArrayList<String> suffix = new ArrayList<>();//转为后缀表达式
int bracket = 0;//前括号个数
JTextArea area;//显示屏
public Calculator() {
}
public void createCalculator () {
JFrame f = new JFrame("简版计算器");
f.setBounds(400,200,300,360);
f.setLayout(new FlowLayout(1,8,12));
//显示屏
area = new JTextArea(4,24);
area.setEditable(false);
f.add(area);
JPanel p = new JPanel();
p.setLayout(new GridLayout(6,6,10,12));
f.add(p);
//按键
JButton bracket1 = new JButton("(");p.add(bracket1);
JButton bracket2 = new JButton(")");p.add(bracket2);
JButton remainder = new JButton("%");p.add(remainder);
JButton division = new JButton("/");p.add(division);
JButton seven = new JButton("7");p.add(seven);
JButton eight = new JButton("8");p.add(eight);
JButton nine = new JButton("9");p.add(nine);
JButton multiplication = new JButton("*");p.add(multiplication);
JButton four = new JButton("4");p.add(four);
JButton five = new JButton("5");p.add(five);
JButton six = new JButton("6");p.add(six);
JButton subtraction = new JButton("-");p.add(subtraction);
JButton one = new JButton("1");p.add(one);
JButton two = new JButton("2");p.add(two);
JButton three = new JButton("3");p.add(three);
JButton addition = new JButton("+");p.add(addition);
JButton power = new JButton("^");p.add(power);
JButton zero = new JButton("0");p.add(zero);
JButton point = new JButton(".");p.add(point);
JButton result = new JButton("=");p.add(result);
JButton clear = new JButton("清屏");p.add(clear);
f.setVisible(true);
Priority();
bracket1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(expression.size() == 0) {
expression.add("(");
area.append("(");
bracket++;
return;
}else{
for(int i = 0; i < Operator.length; i++) {
if(expression.get(expression.size()-1).equals(Operator[i])) {
expression.add("(");
area.append("(");
bracket++;
return;
}
}
new MyDialog("数字之后不可以直接使用前括号!");
}
}
});
bracket2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(expression.size() == 0) {
new MyDialog("不可以直接使用后括号!");
return;
}else{
for(int i = 0; i < Operator.length; i++) {
if(expression.get(expression.size()-1).equals(Operator[i])) {
new MyDialog("运算符后不可以使用后括号!");
return;
}
}
}
if(bracket > 0) {
expression.add(")");
area.append(")");
bracket--;
}else{
new MyDialog("没有前括号与后括号对应~");
}
}
});
remainder.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageSymbol("%");
}
});
division.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageSymbol("/");
}
});
seven.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("7");
}
});
eight.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("8");
}
});
nine.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("9");
}
});
multiplication.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageSymbol("*");
}
});
four.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("4");
}
});
five.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("5");
}
});
six.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("6");
}
});
subtraction.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageSymbol("-");
}
});
one.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("1");
}
});
two.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("2");
}
});
three.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageNum("3");
}
});
addition.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageSymbol("+");
}
});
power.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StorageSymbol("^");
}
});
zero.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(expression.get(expression.size()-1).equals("%") || expression.get(expression.size()-1).equals("/")) {
new MyDialog("分母不可以为零!");
return;
}else{
StorageNum("0");
}
}
});
point.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(expression.size() == 0) {
new MyDialog("小数点使用不规范!");
return;
}else{
if(isNumeric(expression.get(expression.size()-1)) == true) {
int serial = expression.size()-1;
String str = expression.get(serial);
if(str.charAt(str.length()-1) == '.') {
new MyDialog("小数点重复使用!");
return;
}else{
expression.set(serial,expression.get(serial) + ".");
area.append(".");
}
return;
}else{
new MyDialog("小数点使用不规范!");
return;
}
}
}
});
result.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 获取文本框的值
area.append("=");
evalRPN();
Calculate();
}
});
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 获取文本框的值
area.setText("");
expression.clear();
bracket = 0;
suffix.clear();
}
});
}
}
弹窗的代码如下:
public class MyDialog {
public MyDialog(String str) {
JFrame dia = new JFrame();
dia.setLayout(new FlowLayout(1,15,16));
dia.setBounds(450,250,250,120);
JLabel text = new JLabel(str);
dia.add(text);
JButton confirm = new JButton("确定");
dia.add(confirm);
dia.setVisible(true);
confirm.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//内存中释放掉
dia.dispose();
}
});
}
}
4、新的体会
这次算是一次比较仓促的课设,一天激情敲代码搞完的项目,本身质量不算好,但基本操作已经实现,也算是学到了一点点东西。这篇文章还有几个判断的函数没有放进去,想要代码的私信我。其实是很简单的东西,大家还是要动手敲代码,养成自己做项目的流程,效率会提高超多!