数据结构课程设计——算术表达式计算器

目录

一、问题描述

基本要求

二、问题分析

实现思路

三、逻辑设计

1.界面设计

2.程序设计

四、物理设计

1.calculator方法

2.actionPerformed方法

3.infixToSuffix方法

4.result方法

五、源代码

1.Main类

2.calculator类


一、问题描述

 设计一个简单的算术表达式计算器 

基本要求

实现四则运算表达式的求值(包含括号,可多层嵌套)

二、问题分析

目前的计算器大多使用后缀表达式来进行计算,因此基本思想是将用户输入的中缀表达式转为后缀表达式,即逆波兰式,进而由后缀表达式得到计算结果

实现思路

  1. 设置计算器界面,通过用户点击按键来得到待计算的中缀表达式
  2. 将中缀表达式转为后缀表达式
  3. 由后缀表达式得到计算结果,并在计算器界面中显示

三、逻辑设计

1.界面设计

基于Java用户界面设计Swing,采用JFrame框架作为计算器的主窗口,添加文本框来显示用户输入和输出计算结果,并添加具体的计算器按键用于数据输入

1)实现交互:通过为每个按键设置接收操作事件的监听器来得到用户输入数据,当用户鼠标点击按键时触发事件,将按键信息添加到输入文本text中,最终的计算结果会在用户点击等于键时在文本框中显示出来

2)异常处理:为保证系统运行时的稳定性,需要考虑到用户在使用时可能出现的异常情况并进行处理,目前已经实现了以下情况的异常处理,会在文本框内提示Error信息

  1. 表达式中出现除以0的情况
  2. 括号不匹配
  3. 多个运算符连续出现的情况,如1++*2
  4. 一个数字中出现多个小数点,如1.25.9

2.程序设计

设置两个方法分别用于将用户输入的字符串文本转为后缀表达式,以及由后缀表达式得到计算结果

四、物理设计

1.calculator方法

为主窗口设置大小和位置,设置文本框以及每个按键的布局和相关信息,为每个按键添加接收操作事件的监听器

    public Calculator() {
        super("算术表达式计算器");                               //窗体名称
        this.setLayout(null);
        this.setBounds(600, 200, 350, 400);                     //设置窗体位置和大小
        resultText.setBounds(20, 15, 300, 50);                  //设置文本框位置和大小
        resultText.setHorizontalAlignment(JTextField.RIGHT);    //设置文本右对齐
        resultText.setFont(new Font("宋体", Font.PLAIN, 22));   //设置文本字体
        resultText.setEditable(false);
        this.add(resultText);                                 
        int x = 20, y = 80;
        for (int i = 0; i < KEYS.length; i++) {            //设置按键布局
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);                      //设置按键名
            keys[i].setFont(new Font(null, 4, 16));        //设置按键字体
            keys[i].setBounds(x, y, 60, 40);
            if (x < 215) {
                x += 80;
            } else {
                x = 20;
                y += 55;
            }
            this.add(keys[i]);
        }
        for (int i = 0; i < KEYS.length; i++) {                   //为每个按键添加接收操作事件的监听器

            keys[i].addActionListener(this);
        }
        //主窗体的相关设置
        this.setResizable(false);                                 //用户不可调节窗体大小
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);             //窗口关闭方式
        this.setVisible(true);                                    //是否可见
    }

2.actionPerformed方法

设置点击按键后触发的具体事件

    public void actionPerformed(ActionEvent e) {       //设置点击按键时触发的事件
        String tag = e.getActionCommand();
        if (tag.equals("=")) {
            String[] suffix = infixToSuffix(this.text);
            String result = result(suffix);
            this.text = result + "";
            resultText.setText(this.text);
        } else if (tag.equals("AC")) {
            this.text = "";
            resultText.setText("0");
        } else if (tag.equals("π")) {
            this.text += "3.1415926535";
            resultText.setText(this.text);
        } else {
            this.text += tag;
            resultText.setText(this.text);
        }

    }

3.infixToSuffix方法

用于将中缀表达式转为后缀表达式

主要思想:

  1. 遍历中缀表达式,遇到数字直接加入后缀表达式
  2. 遇到操作符时,若比栈顶操作符优先级高则直接压入栈,否则将栈顶运算赋出栈并加入后缀表达式,并继续与栈顶操作赋的优先级比较,直至高于栈顶操作符的优先级时压入栈
  3. 遇到左括号时,将其入栈
  4. 遇到右括号时将操作符从栈顶依次出栈,并加入到后缀表达式中,直至遇到左括号
  5. 遍历完中缀表达式后,将栈内剩余操作符依次出栈并加入后缀表达式

流程图:

 具体代码:

    public String[] infixToSuffix(String text) {          //将中缀表达式转为后缀表达式
        String temp = "";                                 //存放多位字符的情况
        String[] suffix = new String[200];                //存放后缀表达式
        Stack<Character> operator = new Stack<>();        //存放运算符
        int index = 0;
        for (int i = 0; i < text.length(); i++) {
            temp = "";
            char k = text.charAt(i);                      //当前字符
            if (isNumberOrPoint(k)) {
                while (isNumberOrPoint(text.charAt(i))) {
                    temp += String.valueOf(text.charAt(i));
                    i++;
                    if (i >= text.length()) break;
                }
                i--;
                suffix[index++] = temp;
            } else if (k == '+' || k == '-') {
                while (!operator.empty() && operator.peek() != '(') {
                    suffix[index++] = String.valueOf(operator.pop());
                }

                operator.push(k);
            } else if (k == '*' || k == '/') {
                operator.push(k);
            } else if (k == '(') operator.push(k);           //遇到做括号直接入栈
            else if (k == ')') {
                while (operator.peek() != '(') {             //将左括号上方的操作符出栈并加入后缀表达式
                    suffix[index++] = String.valueOf(operator.pop());
                }
                operator.pop();                              //左括号出栈
            }
        }
        while (!operator.empty())                            //将栈中剩余运算符加入后缀表达式
            suffix[index++] = String.valueOf(operator.pop());
        return suffix;

    }

4.result方法

由后缀表达式得到计算结果

主要思想:

  1. 遍历后缀表达式,遇到数字时直接入栈
  2. 遇到操作符时,依次从栈顶取出两个数,根据操作符进行运算,将结果再次入栈,注意操作数顺序,先出栈的应在操作符的右边

流程图:

具体代码:

    public String result(String[] suffix) {                   //根据后缀表达式得到结果
        Stack<String> result = new Stack<>();
        for (int i = 0; suffix[i] != null; i++) {
            if (isNumber(suffix[i])) result.push(suffix[i]);
            else {                                            //为运算符时出栈两个数字经运算后入栈  
                double a = Double.parseDouble(result.pop());
                double b = Double.parseDouble(result.pop());
                if (suffix[i].equals("+")) {
                    result.push(String.valueOf(b + a));
                } else if (suffix[i].equals("-")) {
                    result.push(String.valueOf(b - a));       //注意顺序是反过来的
                } else if (suffix[i].equals("*")) {
                    result.push(String.valueOf(b * a));
                } else if (suffix[i].equals("/")) {
                    if (a == 0) return "Error";
                    else result.push(String.valueOf(b / a));
                }
            }
        }
        return result.peek();

    }

五、源代码

1.Main类

public class Main {
    public static void main(String[] args) {        //程序入口
        Calculator start = new Calculator();

    }
}

2.calculator类

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;

public class Calculator extends JFrame implements ActionListener {
    private String[] KEYS = {"(", ")", "AC", "/", "7", "8", "9", "*", "4", "5", "6", "-", "1", "2", "3", "+", "π", "0", ".", "=",};
    private JButton keys[] = new JButton[KEYS.length];       //计算器中的按钮
    private JTextField resultText = new JTextField("0");   //用于显示结果的文本框,设初值为0
    private String text = "";                                //存放文本

    public Calculator() {
        super("算术表达式计算器");                             //窗体名称
        this.setLayout(null);
        this.setBounds(600, 200, 350, 400);     //设置窗体位置和大小
        resultText.setBounds(20, 15, 300, 50);  //设置文本框位置和大小
        resultText.setHorizontalAlignment(JTextField.RIGHT);     //设置文本右对齐
        resultText.setFont(new Font("宋体", Font.PLAIN, 22));  //设置文本字体
        resultText.setEditable(false);
        this.add(resultText);                //添加文本框
        int x = 20, y = 80;
        for (int i = 0; i < KEYS.length; i++) {     //设置按键布局
            keys[i] = new JButton();
            keys[i].setText(KEYS[i]);        //设置按键名
            keys[i].setFont(new Font(null, 4, 16));       //设置按键字体
            keys[i].setBounds(x, y, 60, 40);
            if (x < 215) {
                x += 80;
            } else {
                x = 20;
                y += 55;
            }
            this.add(keys[i]);
        }
        for (int i = 0; i < KEYS.length; i++) {          //为每个按键添加接收操作事件的监听器

            keys[i].addActionListener(this);
        }
        //主窗体的相关设置
        this.setResizable(false);                      //用户不可调节窗体大小
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);  //窗口关闭方式
        this.setVisible(true);                         //是否可见
    }

    public void actionPerformed(ActionEvent e) {       //设置点击按键时触发的事件
        String tag = e.getActionCommand();
        if (tag.equals("=")) {
            String[] suffix = infixToSuffix(this.text);
            String result = result(suffix);
            this.text = result + "";
            resultText.setText(this.text);
        } else if (tag.equals("AC")) {
            this.text = "";
            resultText.setText("0");
        } else if (tag.equals("π")) {
            this.text += "3.1415926535";
            resultText.setText(this.text);
        } else {
            this.text += tag;
            resultText.setText(this.text);
        }

    }

    public String[] infixToSuffix(String text) {        //将中缀表达式转为后缀表达式
        String temp = "";                                //存放多位字符的情况
        String[] suffix = new String[200];               //存放后缀表达式
        Stack<Character> operator = new Stack<>();       //存放运算符
        int index = 0;
        for (int i = 0; i < text.length(); i++) {
            temp = "";
            char k = text.charAt(i);                     //当前字符
            if (isNumberOrPoint(k)) {
                while (isNumberOrPoint(text.charAt(i))) {
                    temp += String.valueOf(text.charAt(i));
                    i++;
                    if (i >= text.length()) break;
                }
                i--;
                suffix[index++] = temp;
            } else if (k == '+' || k == '-') {
                while (!operator.empty() && operator.peek() != '(') {
                    suffix[index++] = String.valueOf(operator.pop());
                }

                operator.push(k);
            } else if (k == '*' || k == '/') {
                operator.push(k);
            } else if (k == '(') operator.push(k);         //遇到做括号直接入栈
            else if (k == ')') {
                while (!operator.empty() && operator.peek() != '(') {         //将左括号上方的操作符出栈并加入后缀表达式
                    suffix[index++] = String.valueOf(operator.pop());
                }
                if (!operator.empty()) operator.pop();                      //左括号出栈
            }
        }
        while (!operator.empty())                     //将栈中剩余运算符加入后缀表达式
            suffix[index++] = String.valueOf(operator.pop());
        return suffix;

    }

    public boolean isNumberOrPoint(char i) {
        if ((i >= '0' && i <= '9') || i == '.') return true;
        return false;
    }

    public String result(String[] suffix) {             //根据后缀表达式得到结果
        Stack<String> result = new Stack<>();
        for (int i = 0; suffix[i] != null; i++) {
            if (isNumber(suffix[i])) result.push(suffix[i]);
            else {                                      //为运算符时出栈两个数字经运算后入栈

                double a = 0;
                double b = 0;
                try {
                    a = Double.parseDouble(result.pop());
                    b = Double.parseDouble(result.pop());
                } catch (Exception e) {
                    e.printStackTrace();
                    return "Error";

                }

                if (suffix[i].equals("+")) {
                    result.push(String.valueOf(b + a));
                } else if (suffix[i].equals("-")) {
                    result.push(String.valueOf(b - a));   //注意顺序是反过来的
                } else if (suffix[i].equals("*")) {
                    result.push(String.valueOf(b * a));
                } else if (suffix[i].equals("/")) {
                    if (a == 0) return "Error";
                    else result.push(String.valueOf(b / a));
                }
            }
        }
        try {
            return result.peek();
        } catch (Exception e) {
            e.printStackTrace();
            return "Error";
        }

    }

    public boolean isNumber(String t) {                  //判断是否为数字串
        char judge = t.charAt(0);
        if (judge >= '0' && judge <= '9') return true;
        return false;
    }

}

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
目 录 摘 要 1 前 言 2 正 文 3 1. 采用类C语言定义相关的数据类型 3 2. 各模块的伪码算法 5 3. 函数的调用关系图 9 4. 调试分析 10 5. 测试结果 11 6. 源程序(带注释) 14 总 结 22 参考文献 23 致 谢 24 摘 要 目前,计算器应用很广泛,本程序是关于这方面的,其主要功能是进行简单的四则运算 ,其特点之一是支持带括号的四则运算;二是用到栈的一些相关操作,不但对操作有提示,还对与异常输入信息报错。 通过该题目的设计过程,可以加深理解线性表及栈的逻辑结构、存储结构,掌握线性表及栈上基本运算的实现,进一步理解和熟练掌握课本中所学的各种数据结构,学会如何把学到的知识用于解决实际问题,培养学生的动手能力。 关键字:堆栈,初始化栈,入栈,出栈。 前 言 很多涉及计算器程序的的算法都是以栈的相关操作为基础,通过计算器设计,有利于在学习中更好的理解栈及其相关的操作。 通过对计算器计算过程演示,看到了到它的一些性能及相关优势。 我们在写程序时,大框架已成的情况下,仍然发现有些错误很难找到,对于这样的问题,可以利用计算机纠错功能,先运行,再根据题提示修改和完善程序。 在计算器用到的算法中,c语言算法可读性很强,一方面,是因为c语言是高级语言,是面向程序员的语言,二是c语言的功能是很完备的,可以达到事半功倍的效果,和其他语言相比量是比较少。栈的应用使该程序更出色。 正 文 1. 采用类c语言定义相关的数据类型 计算器的演示功能如下: A. 提示输入格式 B. 提示输入 C. 显示输入信息 D. 对有异常的输入报错并重新输入 E. 使用顺序栈实现数据的输入 (1)/*定义堆栈*/ typedef struct{ double data[M]; int top; }Stack; (2)/*初始化堆栈*/ InitStack(Stack *s) { s->top=0; } (3)/*判断栈是否为空*/ int StEmpty(Stack *s) { if(s->top==0) { return 1; } else { return 0; } } (4)/*入栈操作*/ StPush(Stack *s,double x) { if(s->top==M) { printf("The stack is overflow!"); } else { s->top=s->top+1; s->data[s->top]=x; } }
LISP(LISt Processing)是一种基于列表的编程语言,它被广泛用于符号处理和人工智能领域。在LISP中,算术表达式可以表示为列表,其中运算符位于表达式的第一个元素,而操作数位于后续元素。 为了计算LISP算术表达式,您可以使用递归的方式遍历表达式的列表,并根据运算符进行相应的计算。以下是一个简单的LISP算术表达式计算器的示例代码: ```lisp (defun evaluate (expr) (cond ((null expr) 0) ; 空表达式返回0 ((atom expr) expr) ; 单个数字或变量返回本身 (t (let ((operator (car expr)) (operands (cdr expr))) (case operator ((+) (+ (evaluate (car operands)) (evaluate (cadr operands)))) ((-) (- (evaluate (car operands)) (evaluate (cadr operands)))) ((*) (* (evaluate (car operands)) (evaluate (cadr operands)))) ((/) (/ (evaluate (car operands)) (evaluate (cadr operands)))) (t (error "Unknown operator: ~A" operator))))))) ;; 示例用法 (evaluate '(+ 1 2)) ; 3 (evaluate '(- 5 3)) ; 2 (evaluate '(* 4 6)) ; 24 (evaluate '(/ 8 2)) ; 4 ``` 在上述代码中,`evaluate` 函数接受一个表达式作为参数,并使用 `cond` 来根据表达式的类型进行不同的处理。如果表达式是一个空列表,则返回0。如果表达式是一个原子(数字或变量),则直接返回该原子。否则,获取第一个元素作为运算符,剩余元素作为操作数,并使用 `case` 根据运算符进行相应的计算。 请注意,此示例仅支持简单的四则运算,如果要支持更复杂的运算或其他功能,您需要相应地扩展代码。希望这可以帮助到您!如有更多问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值