计算机软件实习实验一:简单计算器的实现(实验准备)

实验内容

1.  学习图形界面的设计, 创建基于对话框的应用程序,添加按钮、编辑框等控件;
 
2.  能通过设计的按钮控件输入并实现简单算术运算,要求表达式在编辑框中显示, 能将运算结果,输出在编辑框内显示;并保存历史的表达式运算记录;
 
3.  也能够实现混合运算的算术表达式求解,算术表达式中包括加、减、乘、除、括号等运算符;并且能够识别括号,优先级正确。

 

实验思路

1. 通过高级程序设计语言(本次使用Java)实现对计算器功能的描述;

2. 通过图形界面框架(本次使用Java swing)实现图形界面可视化(GUI)。

 

涉及知识

数据结构(堆栈),前缀(波兰)/中缀/后缀(逆波兰)表达式的选择与使用;

优先级考虑,Java程序设计,Java swing框架等。

 

具体步骤

1. 学习计算器的几种算法实现,考虑运算符的优先级问题(带括号),决定使用 “双栈算符优先级” 法。

 

2. 使用 Java swing 实现 GUI :下载Java IDE: Eclipse,添加 WindowBuilder 工具包。

 

3. 学习数据结构中关于堆栈的相关知识,以及栈在Java程序中的实现。

①栈:栈(stack)是一种只允许在一端进行插入或删除的线性表。这次实验需要用双栈。

Java定义:

private Stack<Long> numberStack = null;   //数字栈(用于存储表达式中的操作数),设为长整型,初始置空值

private Stack<Character> symbolStack = null;   //符号栈(用于存储表达式中的运算符,包含括号),设为符号型,初始置空值

 

②表达式:使用双栈算符优先级法无需考虑后缀表达式的转换,直接使用中缀表达式即可。

 

③优先级考虑

基本四则运算的优先级;

特别注意括号的优先级。

 

④Java程序设计

学习Java的基本语法和格式;

了解关于栈、swing等包的接口调用;

//图形界面
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

//栈
import java.util.Stack;

//swing框架
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

写好注释方便以后调试。

 

⑤Java swing框架

顶层容器 JFrame,中间容器 JPanel 等的创建和使用;

JFrame win = new JFrame("计算器");
JPanel pa = new JPanel();

基本组件 JButton 等的创建和使用;

 JButton bn = new JButton("计算");

不可编辑信息的显示组件 JLabel 等的创建和使用;

JPanel pa = new JPanel();

可编辑单行文本组件 JTextField 等的创建和使用。

final JTextField formulaText = new JTextField(num, 20);

 

实验元素

1.实验总体框架:

 

2.具体算法:

①双栈算法

StringBuffer temp = new StringBuffer(); 
for (int i = 0; i < numStr.length(); i++) {
            char s = numStr.charAt(i);   
            if (isNumber(s)) {   //若当前字符是数字
                temp.append(s); //加入到数字缓存中
            } 
            else {   //若当前字符是运算符(含括号)
                String tempStr = temp.toString();   //转为字符串
                if (!tempStr.isEmpty()) {
             long num = Long.parseLong(tempStr);   //转为长整型数
                    numberStack.push(num);   //将长整型运算符压栈
                    temp = new StringBuffer();   //重置数字缓存
                }
 }

 

②运算符优先级比较算法

for (int i = 0; i < numStr.length(); i++) { 
private boolean comparePri(char symbol) {
        if (symbolStack.empty()) {   //空栈返回true
            return true;
        }

        char top = (char) symbolStack.peek();   //符号栈顶部对象
        if (top == '(') {
            return true;
        }
        //比较优先级
        switch (symbol) {
        case '(':   //优先级最高
            return true;
        case '*': {
            if (top == '+' || top == '-')   //优先级比+和-高
                return true;
            else
                return false;
        }
        case '/': {
            if (top == '+' || top == '-')   //优先级比+和-高
                return true;
            else
                return false;
        }
        case '+':
            return false;
        case '-':
            return false;
        case ')':   //优先级最低
            return false;
        case '=':   //结束符
            return false;
        default:
            break;
        }
        return true;
    }
}

 

3.完整源码。

//图形界面
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
//栈
import java.util.Stack;
 
//swing框架
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Calculator {
    //数字栈:用于存储表达式中的各个数字
    private Stack<Double> numberStack = null;
    
    //符号栈:用于存储运算符和括号
    private Stack<Character> symbolStack = null;

    //解析并计算四则运算表达式(含括号)
    public double calculate(String numStr) {
        numStr = removeStrSpace(numStr);   //去除空格
        
        //如果算术表达式尾部没有‘=’号,则在尾部添加结束符‘=’
        if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
            numStr += "=";
        }
        //检查表达式是否合法
        if (!isStandard(numStr)) {
            System.err.println("错误:算术表达式有误!");
            return 0;
        }
        
        //初始化栈
        numberStack = new Stack<Double>();
        symbolStack = new Stack<Character>();
        
        //用于缓存数字,因为数字可能是多位的
        StringBuffer temp = new StringBuffer();
        
        //从表达式的第一个字符开始处理
        for (int i = 0; i < numStr.length(); i++) {
            char s = numStr.charAt(i);   //获取一个字符
            if (isNumber(s)) {   //若当前字符是数字
                temp.append(s);   //加入到数字缓存中
            } 
            else {   //若当前字符是运算符(含括号)
                String tempStr = temp.toString();   //将运算符缓存转为字符串
                if (!tempStr.isEmpty()) {
                    double num = Double.parseDouble(tempStr);   //将运算符字符串转为长整型数
                    numberStack.push(num);   //将长整型运算符压栈
                    temp = new StringBuffer();   //重置数字缓存
                }
                
                //判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把前面两个数字取出来
                while (!comparePri(s) && !symbolStack.empty()) {
                    double b = numberStack.pop();   //出栈,取出数字,后进先出
                    double a = numberStack.pop();
                    
                    //取出运算符进行运算,并把结果压栈
                    switch ((char) symbolStack.pop()) {   //强制转换为字符串
                    case '+':
                        numberStack.push(a + b);
                        break;
                    case '-':
                        numberStack.push(a - b);
                        break;
                    case '*':
                        numberStack.push(a * b);
                        break;
                    case '/':
                        numberStack.push(a / b);
                        break;
                    default:
                        break;
                    }
                }   //while循环结束
                
                if (s != '=') {
                    symbolStack.push(s);   //将运算结果压入符号栈
                    if (s == ')') {   //如果是括号,先去掉括号再弹出运算符
                        symbolStack.pop();
                        symbolStack.pop();
                    }
                }
            }
        }   //for循环结束

        return numberStack.pop();   //返回计算结果
    }

    //去除字符串中的所有空格
    private String removeStrSpace(String str) {
        return str != null ? str.replaceAll(" ", "") : "";
    }

    //检查算术表达式的基本合法性,符合返回true,否则false
    private boolean isStandard(String numStr) {
        if (numStr == null || numStr.isEmpty())   //表达式不能为空
            return false;
        Stack<Character> stack = new Stack<Character>();   //用来保存括号,检查左右括号是否匹配
        boolean b = false;   //用来标记'='是否存在多个
        for (int i = 0; i < numStr.length(); i++) {
            char n = numStr.charAt(i);
            //如果运算符中含有数字或者有连续的运算符则返回false
            if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
                    || "+".equals(n + "") || "-".equals(n + "")
                    || "*".equals(n + "") || "/".equals(n + "")
                    || "=".equals(n + ""))) {
                return false;
            }
            
            //将左括号压栈与后面的右括号进行匹配
            if ("(".equals(n + "")) {
                stack.push(n);
            }
            if (")".equals(n + "")) {   //匹配括号
                if (stack.isEmpty() || !"(".equals((char) stack.pop() + ""))   //括号是否匹配
                    return false;
            }
            //检查是否有多个'='号,最后一个元素弹出前有括号则返回false
            if ("=".equals(n +" ")) {
                if (b)
                    return false;
                b = true;
            }
        }
        
        //可能会有缺少右括号的情况
        if (!stack.isEmpty())
            return false;
        return true;
    }

    //判断字符是否是0-9的数字
    private boolean isNumber(char num) {
        if (num >= '0' && num <= '9')
            return true;
        return false;
    }

    //如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
    private boolean comparePri(char symbol) {
        if (symbolStack.empty()) {   //空栈返回true
            return true;
        }

        //符号优先级说明(从高到低):
        //第1级: (
        //第2级: * /
        //第3级: + -
        //第4级: )

        char top = (char) symbolStack.peek();   //查看符号堆栈顶部的对象
        if (top == '(') {
            return true;
        }
        //比较优先级
        switch (symbol) {
        case '(':   //优先级最高
            return true;
        case '*': {
            if (top == '+' || top == '-')   //优先级比+和-高
                return true;
            else
                return false;
        }
        case '/': {
            if (top == '+' || top == '-')   //优先级比+和-高
                return true;
            else
                return false;
        }
        case '+':
            return false;
        case '-':
            return false;
        case ')':   //优先级最低
            return false;
        case '=':   //结束符
            return false;
        default:
            break;
        }
        return true;
    }

    //主方法实现图形界面
    public static void main(String args[]) {
        String num = null;
        
        //创建一个窗口
        JFrame fra = new JFrame("计算器");   //GUI名字
        Container con = fra.getContentPane();
        JPanel pan = new JPanel();
        pan.add(new JLabel("输入运算式:"));   //添加一个标签
        final JTextField formulaText = new JTextField(num, 20);   //算式输入框
        pan.add(formulaText);
        pan.add(new JLabel("="));
        final JTextField resultText = new JTextField(10);   //结果文本框
        pan.add(resultText);
        con.add(pan);  //将组件pan放置到容器con中

        //界面布局
        JButton bn = new JButton("计算");   //实例化按钮对象
        con.add(bn, BorderLayout.EAST);   //将按钮添加到右边
        fra.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   //设置关闭窗口退出程序
        fra.pack();   //自动调整窗口大小
        fra.setLocationRelativeTo(null);   //设置窗口居中于屏幕
        fra.setVisible(true);   //显示窗口

        //添加按钮点击事件
        bn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {   //每当按钮点击时调用该方法
               
            	Calculator cal = new Calculator();   //计算器操作
                String numStr = formulaText.getText();   //获得算式文本框中的文字
                double result = cal.calculate(numStr);   //计算算式的结果
                numStr = cal.removeStrSpace(numStr);   //去空格
                formulaText.setText(numStr);   //将去空格的算式放回算式文本框中
                resultText.setText(result + "");   //在结果文本框中显示结果
            }
        });
    }
}

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值