实验内容:
- 学习GUI图形界面的设计,Python Tinker或 Java Swing/Awt 或C++ QT框架,创建交互友好的应用程序;
- 能通过界面按钮控件输入并实现算术表达式,输入的表达式即时在控件中显示,按下“=”按钮能实现运算,并将运算结果输出在控件中显示;要求能保存和浏览历史表达式的运算记录。
- 算术表达式求解,是指算术表达式中包括加、减、乘、除、括号等运算符,能求解包含括号的四则混合运算;并且能够检验表达式的合法性。
- 选做:①实现三角函数的运算、对数运算、指数运算、进制转换等; ②设计函数,分别求两个一元多项式的乘积与和。
实验思路:
- 首先在数学上,运算规则是: 先乘除,后加减,从左到右算,先括号内,后括号外。除去一些基本运算符,还有很多其他的运算符。所以判断运算符的优先级尤为重要。
- 其次对于输入的算术表达式在计算机看来是一串字符串,我们要如何让它明白我们输入的是数字还是一个运算符,如果是数字,又该怎样让连续数字合并为一个整体。
- 如果以上都能实现了,那么就可以进行运算了。在这开始前我们要知道两个算法表达式:
- 中缀表达式 A+(B-C/D)*E
- 后缀表达式 ABCD/-E*+
我们平常用的都是中缀表达式,但是在计算机中用后缀表达式会更加方便,因为有先进先出的 “队列结构”和先进后出的“栈结构”。运用这两种存储结构可以很方便的就进行运算。所以我们要把中缀表达式转化为后缀表达式。有以下几个原则:
从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:
(1)如果X是操作数,直接入队
(2)如果X是运算符,再分以下情况:
a)如果栈为空,直接入栈。
b)如果X==”(“,直接入栈。
c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一个配对的”(”出栈。(注:“(”和“)”都不 入队)
d)如果是其他操作符(+ - * /),则和栈顶元素进行比较优先级。 如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。
(3)最后将栈中剩余的操作符全部入队。
以 A+(B-C/D)*E 为例,先定义一个用来暂时存放操作符的栈 OpStack,再定义一个用来存放后缀表达式的队列 PostQueue。 我们要从左至右遍历 A+(B-C/D)*E,
- A,是操作数,放入队列 PostQueue。 此时, PostQueue:A;OpStack:null。
- +,是运算符,根据(2).a 的原则,放入栈 OpStack。此时, PostQueue:A;OpStack:+。
- (,是运算符,根据(2).b,放入栈 OpStack。此时, PostQueue:A;OpStack:+,(。
- B,是操作数,放入队列 PostQueue。此时, PostQueue:A,B;OpStack:+,(。
- -,是运算符,因为位于栈顶的是“(”,所以放入栈 OpStack。此时PostQueue:A,B;OpStack:+,(,-。
- C,是操作数,放入队列 PostQueue。此时,PostQueue:A,B,C;OpStack:+,(,-。
- /,是运算符,且优先级大于“*-”,所以放入栈 OpStack。此时,PostQueue:A,B,C;OpStack:+,(,-,/。
- D,是操作数,放入队列 PostQueue。此时,PostQueue:A,B,C,D;OpStack:+,(,-,/。
- ),根据(2).c,一次弹出栈顶元素并放入队列直至“(”。此时,PostQueue:A,B,C,D,/,-;OpStack:+。
- *,是运算符,因为优先级比“+”高,所以入栈。此时,PostQueue:A,B,C,D,/,-;OpStack:+,*。
- E,是操作数,放入队列 PostQueue。此时,PostQueue:A,B,C,D,/,-,E;OpStack:+,*。
- 中缀表达式以遍历完毕,所以将栈内元素依次弹出放入队列。此时,PostQueue:A,B,C,D,/,-,E,*,+;OpStack:null。
这就是中缀表达式转后缀表达式的基本思路的基本思路。这一步的代码:
代码开头的定义之类的
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class 计算器窗口 extends JFrame {
JTextField jTextField = new JTextField("");
JPanel jPanel = new JPanel(new GridLayout(5, 4, 5, 3));
JTextArea jTextArea2 = new JTextArea(""); //文本域,显示各个按钮的功能
String[] str = new String[]{"AC", "(", ")", "/", "<-", "7", "8", "9", "*",
"^", "4", "5", "6", "-", "+", "1", "2", "3", "~",
"记录回调", "%", "0", ".", "历史记录", "="}; //各按钮及名称
static Stack opStack = new Stack(); //建立操作符栈
static String x = ""; //存放连续的数字
static Stack<String> Res_Stack = new Stack(); //存放运算结果的栈
static Queue<String> postQueue = new LinkedList(); //表达式队列
static int num = 0;
static int numx = 0; //连续的数字的个数
static boolean flag1 = false; //对是否是连续数字和小数的判断
static boolean flag2 = false; //用于判断负数
static Stack<String> Hos1_Stack = new Stack(); //历史记录栈1
static Stack<String> Hos2_Stack = new Stack(); //历史记录栈2
static boolean flag3 = true;
判断字符方法的部分,这步过程略长,我分了多种情况:
一