实验一、支持算术表达式求解的计算器

实验任务:

(1)能通过设计的按钮控件输入并实现算术表达式,表达式在文本框中显示,运算结果输出显示;保存和浏览历史运算记录;

(2)能够检验算术表达式的合法性;

(3)能够实现混合运算的求解,算术表达式中包括加、减、乘、除、括号等运算符;

(4)要求交互界面友好,程序健壮。

概述:本实验主要是Java swing的编写,重点讲述利用java语言实现一个简单计算器。开发环境用的是idea。

实验步骤:

一.中缀表达式转换为后缀表达式,以及后缀表达式的计算

1.什么是中缀表达式和后缀表达式

  中缀表达式     A+(B-C/D)*E 

   后缀表达式     ABCD/-E*+  

2.算法思想:

从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:

(1)如果X是操作数,直接入队

(2)如果X是运算符,再分以下情况:

 a)如果栈为空,直接入栈。

 b)如果X==”(“,直接入栈。

 c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一个配对的”(”出栈。(注:“(”和“)”都不 入队)    

  d)如果是其他操作符(+ - * /),则和栈顶元素进行比较优先级。 如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。

(3)最后将栈中剩余的操作符全部入队。

3.后缀表达式求解

1.从左至右开始遍历后缀表达式的元素;

2.如果遇到的元素是操作数,就入栈,如果是运算符,就把两个数字拿出来运算之后结果入栈,直到,全部遍历一遍,输出结果

4.编程实现:

//将中缀表达式转换为后缀表达式
private String[] Suffix(String str) {
    String s = "";// 用于承接多位数的字符串
    char[] Stack = new char[100];// 静态栈,对用户输入的操作符进行处理,用于存储运算符
    String[] postQueue = new String[100];// 后缀表达式字符串数组,为了将多位数存储为独立的字符串
    int top = -1, j = 0;// 静态指针top,控制变量j
    for (int i = 0; i < str.length(); i++)// 遍历中缀表达式
    // indexof函数,返回字串首次出现的位置;charAt函数返回index位置处的字符;
    {
        if ("0123456789.".indexOf(str.charAt(i)) >= 0) // 遇到数字字符的情况直接入队
        {
            s = "";// 作为承接字符,每次开始时都要清空
            for (; i < str.length() && "0123456789.".indexOf(str.charAt(i)) >= 0; i++) {
                s = s + str.charAt(i);
                //比如,中缀表达式:234+4*2,我们扫描这个字符串的时候,s的作用相当于用来存储长度为3个字符的操作数:234
            }
            i--;
            postQueue[j] = s;// 数字字符直接加入后缀表达式
            j++;
        } else if ("(".indexOf(str.charAt(i)) >= 0) {// 遇到左括号
            top++;
            Stack[top] = str.charAt(i);// 左括号入栈
        } else if (")".indexOf(str.charAt(i)) >= 0) {// 遇到右括号
            for (; ; )// 栈顶元素循环出栈,直到遇到左括号为止
            {
                if (Stack[top] != '(') {// 栈顶元素不是左括号
                    postQueue[j] = Stack[top] + "";// 栈顶元素出栈
                    j++;
                    top--;
                } else { // 找到栈顶元素是左括号
                    top--;// 删除栈顶左括号
                    break;// 循环结束
                }
            }
        } else if ("*÷+-%".indexOf(str.charAt(i)) >= 0)// 遇到运算符
        {
            if (top == -1) {// 若栈为空则直接入栈
                top++;
                Stack[top] = str.charAt(i);
            } else if ("*÷%".indexOf(Stack[top]) >= 0) {// 当栈顶元素为高优先级运算符时,让栈顶元素出栈进入后缀表达式后,当前运算符再入栈
                postQueue[j] = Stack[top] + "";
                j++;
                Stack[top] = str.charAt(i);
            } else {
                top++;
                Stack[top] = str.charAt(i);// 当前元素入栈
            }
        }
    }
    while (top != -1) {// 遍历结束后将栈中剩余元素依次出栈进入后缀表达式
        postQueue[j] = Stack[top] + "";
        j++;
        top--;
    }
    return postQueue;
}

// 计算后缀表达式,并返回最终结果
public String Result(String[] str) {
    String[] Result = new String[100];// 顺序存储的栈,数据类型为字符串
    int Top = -1;// 静态指针Top
    for (int i = 0; str[i] != null; i++) {
        if (!"+-*÷%".contains(str[i])) {  //遇到数字,直接入栈
            Top++;
            Result[Top] = str[i];
        }
        if ("+-*÷%".contains(str[i]))// 遇到运算符字符,将栈顶两个元素出栈计算并将结果返回栈顶
        {
            double x, y, n;
            x = Double.parseDouble(Result[Top]);// 顺序出栈两个数字字符串,并转换为double类型
            Top--;
            y = Double.parseDouble(Result[Top]);
            Top--;
            if ("*".contains(str[i])) {
                n = y * x;
                Top++;
                Result[Top] = String.valueOf(n);// 将运算结果重新入栈

            }
            if ("÷".contains(str[i])) {
                if (x == 0)// 被除数不允许为0
                {
                    String s = "error!";
                    return s;
                } else {
                    n = y / x;
                    Top++;
                    Result[Top] = String.valueOf(n);// 将运算结果重新入栈
                }
            }
            if ("-".contains(str[i])) {
                n = y - x;
                Top++;
                Result[Top] = String.valueOf(n);// 将运算结果重新入栈
            }
            if ("+".contains(str[i])) {
                n = y + x;
                Top++;
                Result[Top] = String.valueOf(n);// 将运算结果重新入栈
            }
            if ("%".indexOf(str[i]) >= 0) {
                if (x == 0)//不允许被除数为0
                {
                    String s = "ERROR";
                    return s;
                } else {
                    n = y % x;
                    Top++;
                    Result[Top] = String.valueOf(n);
                }
           }
        }
    }
    return Result[Top];// 返回最终结果
}

二.文本框与历史记录

需要用到让类calculator继承JFrame类,实现事件监听,并在构造方法类中进行布局和使用约束。

编程实现:

//Calculator类,继承JFrame框架,实现事件监听器接口
public class calculator extends JFrame implements ActionListener {
    private final String[] KEYS = {"7", "8", "9", "AC", "4", "5", "6", "-", "1", "2", "3", "+", "%", "0", "÷",
            "*", "(", ".", ")", "="};
    private JButton keys[] = new JButton[KEYS.length];
    private JTextArea resultText = new JTextArea("0.0");// 文本域组件TextArea可容纳多行文本;文本框内容初始值设为0.0
    private JTextArea History = new JTextArea();// 历史记录文本框初始值设为空
    private JPanel jp2 = new JPanel();
    private JScrollPane gdt1 = new JScrollPane(resultText);//给输入显示屏文本域新建一个垂直滚动滑条
    private JScrollPane gdt2 = new JScrollPane(History);//给历史记录文本域新建一个垂直滚动滑条
    // private JScrollPane gdt3=new JScrollPane(History);//给历史记录文本域新建一个水平滚动滑条
    private JLabel label = new JLabel("历史记录");
    private String b = "";

    // 构造方法
    public calculator() {
        super("Calculator");//“超”关键字,表示调用父类的构造函数,
        resultText.setBackground(Color.LIGHT_GRAY);
        History.setBackground(Color.LIGHT_GRAY);
        resultText.setFont(new Font("楷体", Font.BOLD, 20));
        resultText.setBounds(20, 18, 255, 115);// 设置文本框大小
        resultText.setAlignmentX(RIGHT_ALIGNMENT);// 文本框内容右对齐
        resultText.setEditable(false);// 文本框不允许修改结果
        History.setBounds(20, 36, 255, 115);// 设置文本框大小
        History.setAlignmentX(LEFT_ALIGNMENT);// 文本框内容右对齐
        History.setEditable(false);// 文本框不允许修改结果
        label.setBounds(20, 65, 100, 20);//设置标签位置及大小
        jp2.setBounds(20, 85, 255, 60);//设置面板窗口位置及大小
        jp2.setLayout(new GridLayout());
        JPanel jp1 = new JPanel();
        jp1.setBounds(20, 9, 255, 60);//设置面板窗口位置及大小
        jp1.setLayout(new GridLayout());
        resultText.setLineWrap(true);// 激活自动换行功能
        resultText.setSelectedTextColor(Color.RED);
        History.setLineWrap(true);//自动换行
        History.setWrapStyleWord(true);
        History.setSelectedTextColor(Color.blue);
        gdt1.setViewportView(resultText);//使滚动条显示出来
        gdt2.setViewportView(History);
        jp1.add(gdt1);//将滚动条添加入面板窗口中
        jp2.add(gdt2);
        this.add(jp1);//将面板添加到总窗体中
        this.add(jp2);//将面板添加到总窗体中
        this.setLayout(null);
        this.add(label);// 新建“历史记录”标签

        // 放置按钮
        int x = 20, y = 150;
        for (int i = 0; i < KEYS.length; i++) {
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);
            keys[i].setBounds(x, y, 60, 40);
            if (x < 215) {
                x += 65;
            } else {
                x = 20;
                y += 45;
            }
            this.add(keys[i]);
        }
        for (int i = 0; i < KEYS.length; i++)// 每个按钮都注册事件监听器
        {
            keys[i].addActionListener(this);
        }
        this.setResizable(false);
        this.setBounds(500, 200, 310, 420);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    // 事件处理
    public void actionPerformed(ActionEvent e) {
        String label = e.getActionCommand();//获得事件源的标签

        if (Objects.equals(label, "=")) {
            resultText.setText(this.b);
            History.setText(History.getText() + resultText.getText());

            if (label.equals("="))//调用计算方法,得出最终结果
            {
                String[] s = Suffix(this.b);
                String result = Result(s);
                this.b = result + "";
                //更新文本框,当前结果在字符串b中,并未删除,下一次输入接着此结果以实现连续运算
                resultText.setText(this.b);
                History.setText(History.getText() + "=" + resultText.getText() + "\n");
            }
        } else if (Objects.equals(label, "AC"))//清空按钮,消除显示屏文本框前面所有的输入和结果
        {
            this.b = "";
            resultText.setText("0");//更新文本域的显示,显示初始值;
        } else {
            this.b = this.b + label;
            resultText.setText(this.b);
        
        }
    }
实验结果:

实验总结:通过这次实验学习了GUI图形界面的设计,入门了Java Swing框架,强化了自己的代码能力。

不足:实现功能较少;

           不能检测是否多个运算符连续输入;

           没有设置界面样式。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值