Java实验报告C语言实训支持表达式计算器.docx
《Java实验报告C语言实训支持表达式计算器.docx》由会员分享,可在线阅读,更多相关《Java实验报告C语言实训支持表达式计算器.docx(22页珍藏版)》请在冰豆网上搜索。
Java实验报告C语言实训支持表达式计算器
C语言程序设计实训
报告书
班级惠普测试142
学号1408090213
姓名闫伟明
指导教师庞志永
实训项目名称:
支持表达式求值的计算器的设计与实现
1.实训目的
所设计的计算器可以进行简单的表达式求值,并支持括号运算。
通过该课程设计,了解数组的使用,学会用函数实现栈等操作。
2.实训要求
(1)应用所学知识,完成实训目标。
(2)程序能够正常运行,运算结果正确,满足设计要求。
3.功能描述
要求程序具有输入界面,该输入界面至少有一个文本框和一个按钮。
用户在文本输入框内输入需要计算的表达式,并单击按钮后,程序可以计算出该表达式的值。
用户输入的表达式可能是符合数学规则的表达式,也可能是不符合数学规则的表达式。
如果输入的表达式正确,则计算器能够给出正确结果,否则,程序输出错误信息,并尽可能指出错误的位置及错误的类型。
4.总体设计
5.程序实现及相关描述
前缀表达式(前缀记法、波兰式)
前缀表达式的运算符位于操作数之前。
前缀表达式的计算机求值:
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素op次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。
例如前缀表达式“-×+3456”:
(1)从右至左扫描,将6、5、4、3压入堆栈;
(2)遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做比较),计算出3+4的值,得7,再将7入栈;
(3)接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈;
(4)最后是-运算符,计算出35-6的值,即29,由此得出最终结果。
可以看出,用计算机计算前缀表达式的值是很容易的。
将中缀表达式转换为前缀表达式:
遵循以下步骤:
*
(1)初始化两个栈:
运算符栈S1和储存中间结果的栈S2;
*
(2)从右至左扫描中缀表达式;
*(3)遇到操作数时,将其压入S2;
*(4)遇到运算符时,比较其与S1栈顶运算符的优先级:
*(4-1)如果S1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈;
*(4-2)否则,若优先级比栈顶运算符的较高或相等,也将运算符压入S1;
*(4-3)否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
*(5)遇到括号时:
*(5-1)如果是右括号“)”,则直接压入S1;
*(5-2)如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃;
*(6)重复步骤
(2)至(5),直到表达式的最左边;
*(7)将S1中剩余的运算符依次弹出并压入S2;
*(8)依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
例如,将中缀表达式“1+((2+3)×4)-5”转换为前缀表达式的过程如下:
扫描到的元素
S2(栈底->栈顶)
S1(栈底->栈顶)
说明
5
5
空
数字,直接入栈
-
5
-
S1为空,运算符直接入栈
)
5
-)
右括号直接入栈
4
54
-)
数字直接入栈
×
54
-)×
S1栈顶是右括号,直接入栈
)
54
-)×)
右括号直接入栈
3
543
-)×)
数字
+
543
-)×)+
S1栈顶是右括号,直接入栈
2
5432
-)×)+
数字
(
5432+
-)×
左括号,弹出运算符直至遇到右括号
(
5432+×
-
同上
+
5432+×
-+
优先级与-相同,入栈
1
5432+×1
-+
数字
到达最左端
5432+×1+-
空
S1中剩余的运算符
运行截图:
6.本实训中遇到的关键问题及其解决方法:
中缀表达式(中缀记法)
中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。
中缀表达式是人们常用的算术表示方法。
虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。
对计算机来说,计算前缀或后缀表达式的值非常简单。
7.实训总结:
通过一个简单的计算器程序,让我对java编程及栈的操作有了进一步的认识。
认识到需要培养团队合作能力。
8.附录:
程序实现代码:
MainFrame.java
importjavax.swing.*;
importjavax.swing.border.Border;
importjava.awt.*;
importjava.awt.event.ActionListener;
importjava.awt.event.ActionEvent;
importjava.awt.event.KeyAdapter;
importjava.awt.event.KeyEvent;
/**
*我的计算器。
MainFrame继承于JFrame,是计算器的界面
*/
publicclassMainFrameextendsJFrame{
/**
*
*/
privatestaticfinallongserialVersionUID=1L;
privateBorderborder=BorderFactory.createEmptyBorder(5,5,5,5);
privateJTextFieldtextbox=newJTextField("0");
privateJTextFieldoldtextbox=newJTextField("0");
privateJTextFieldqz_textbox=newJTextField("0");
StringBuildersbBuilder=newStringBuilder("");//输入缓存
//按下=或回车得到结果
voidgetResult(){
if(!
sbBuilder.toString().equals(textbox.getText())){
intend=sbBuilder.length();
sbBuilder=sbBuilder.delete(0,end);
sbBuilder.append(textbox.getText());
}
Stringstring=null;
String[]results=null;
try{
string=sbBuilder.toString();
if(string.matches(".*[=\\-*/]")){
thrownewException("运算符格式不正确!
");
}elseif(string.matches("[+\\-*/][0-9]*.*")){
string=sbBuilder.insert(0,'0').toString();
}
results=Calculator.toPolishNotation(string);
}catch(Exceptione){
string="0";
sbBuilder=newStringBuilder("0");
results=newString[]{"0","0"};
JOptionPane.showMessageDialog(this,"表达式格式错误。
"+e.getMessage());
}
StringoResult=results[0];//
oldtextbox.setText(string);
qz_textbox.setText(results[1]);
textbox.setText(oResult);
intend=sbBuilder.length();
//System.out.println(end);
sbBuilder.delete(0,end);
sbBuilder.append(oResult);
return;
}
privateActionListenerlistener=newActionListener(){
publicvoidactionPerformed(ActionEvente){
JButtonb=(JButton)e.getSource();
Stringlabel=b.getText();
if(label.equals("=")){
getResult();
}elseif(label.equals("DEL")){
intend=sbBuilder.length();
sbBuilder=sbBuilder.deleteCharAt(end-1);
textbox.setText(sbBuilder.toString());
}elseif(label.equals("C")){
intend=sbBuilder.length();
sbBuilder=sbBuilder.delete(0,end);
textbox.setText(sbBuilder.toString());
oldtextbox.setText("CLEAR");
}
else{
sbBuilder.append(label);
textbox.setText(sbBuilder.toString());
}
}
////
};
publicMainFrame(Stringtitle)throwsHeadlessException{
super(title);//调用父类构造方法
setupFrame();//调整窗体属性
setupControls();//创建控件
}
privatevoidsetupControls(){
setupDisplayPanel();//创建文本面板
setupButtonsPanel();//创建按钮面板
}
//创建按钮面板并添加按钮
privatevoidsetupButtonsPanel(){
JPanelpanel=newJPanel();
panel.setBorder(border);
panel.setLayout(newGridLayout(4,5,3,3));
createButtons(panel,newString[]{
"7","8","9","+","DEL",
"4","5","6","-","C",
"1","2","3","*","(",//空字符串表示这个位置没有按钮
"0",".","=","/",")"});
this.add(panel,BorderLayout.SOUTH);
}
/**
*在指定的面板上创建按钮
*
*@parampanel
*要创建按钮的面板
*@paramlabels
*按钮文字
*/
privatevoidcreateButtons(JPanelpanel,String[]labels){
for(Stringlabel:
labels){
//如果label为空,则表示创建一个空面板。
否则创建一个按钮。
if(label.equals("")){
panel.add(newJPanel());
}else{
JButtonb=newJButton(label);
b.setFont(newFont("微软雅黑",Font.PLAIN,20));
b.addActionListener(listener);//为按钮添加侦听器
panel.add(b);
}
}
}
//设置显示面板,用一个文本框来作为计算器的显示部分。
privatevoidsetupDisplayPanel(){
JPanelpanel=newJPanel();
JPanelpanel1=newJPanel();
panel.setLayout(newBorderLayout());
panel.setBorder(border);
panel1.setLayout(newBorderLayout());
panel1.setBorder(border);
setupTextbox();
panel1.add(qz_textbox,BorderLayout.CENTER);
panel.add(oldtextbox,BorderLayout.NORTH);
panel.add(textbox,BorderLayout.CENTER);
this.add(panel1,BorderLayout.NORTH);
this.add(panel,BorderLayout.CENTER);
}
//调整文本框
privatevoidsetupTextbox(){
qz_textbox.setHorizontalAlignment(JTextField.RIGHT);//文本右对齐
qz_textbox.setEditable(false);
textbox.setHorizontalAlignment(JTextField.RIGHT);//文本右对齐
textbox.setEditable(true);//文本框只读
//按下ENTER键得到结果
textbox.addKeyListener(newKeyAdapter(){
@Override
publicvoidkeyReleased(KeyEvente){
if(e.getKeyCode()==KeyEvent.VK_ENTER){
getResult();
}
}
});
textbox.setBackground(Color.white);//文本框背景色为白色
qz_textbox.setBackground(Color.white);//文本框背景色为白色
oldtextbox.setHorizontalAlignment(JTextField.RIGHT);//文本右对齐
oldtextbox.setEditable(false);//文本框只读
oldtextbox.setBackground(Color.white);//文本框背景色为白色
oldtextbox.setBorder(BorderFactory.createEmptyBorder(5,5,0,5));
textbox.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
qz_textbox.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
textbox.setFont(newFont("微软雅黑",Font.BOLD,20));
oldtextbox.setFont(newFont("微软雅黑",Font.PLAIN,16));
//TODO让文本框一进入程序就能获得输入焦点
}
//调整窗体
privatevoidsetupFrame(){
this.setDefaultCloseOperation(EXIT_ON_CLOSE);//当窗体关闭时程序结束
this.setLocation(100,50);//设置窗体显示在桌面上的位置
this.setSize(400,300);//设置窗体大小
this.setResizable(false);//窗体大小固定
}
//程序入口
publicstaticvoidmain(String[]args)throwsException{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
MainFrameframe=newMainFrame("支持表达式求值的计算器的设计与实现");
frame.setVisible(true);//在桌面上显示窗体
}
}
Calculator.java
importjava.util.Stack;
/**
*
*利用栈实现中缀表达式计算
*@author
*
*/
publicclassCalculator{
/**
*转换成前缀表达式并计算.
*
*将中缀表达式转换为前缀表达式:
*遵循以下步骤:
*
(1)初始化两个栈:
运算符栈S1和储存中间结果的栈S2;
*
(2)从右至左扫描中缀表达式;
*(3)遇到操作数时,将其压入S2;
*(4)遇到运算符时,比较其与S1栈顶运算符的优先级:
*(4-1)如果S1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈;
*(4-2)否则,若优先级比栈顶运算符的较高或相等,也将运算符压入S1;
*(4-3)否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
*(5)遇到括号时:
*(5-1)如果是右括号“)”,则直接压入S1;
*(5-2)如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃;
*(6)重复步骤
(2)至(5),直到表达式的最左边;
*(7)将S1中剩余的运算符依次弹出并压入S2;
*(8)依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
*@param表达式字符串
*@return计算结果Object[2][0]:
Doubleresult[1]:
Stringexpression
*@throwsIllegalArgumentException
*@throwsNumberFormatException
*/
publicstaticString[]toPolishNotation(Stringinput)
throwsIllegalArgumentException,NumberFormatException{
//string:
1+3*(2-1)
intlen=input.length();//len:
9
charc,tempChar;
Stacks1=newStack();//操作运算符
Stacks2=newStack();//中间结果
Stack
doublenumber;
intlastIndex=-1;
for(inti=len-1;i>=0;--i){//8-0
c=input.charAt(i);//i:
8c:
)
if(Character.isDigit(c)){
//i:
7c:
1自右向左找到input中最后一个数的最后一位数字的下标
lastIndex=readDoubleReverse(input,i);
//lastIndex(input中最后一个数的第一位数字的下标):
7
number=Double.parseDouble(input.substring(lastIndex,i+1));
//找到input中最后一个数:
number
s2.push(number);//遇到操作数时,将其压入S2;
i=lastIndex;
//将前缀表达式压入expression栈
if((int)number==number)
expression.push((int)number);
else
expression.push(number);
}elseif(isOperator(c)){
//遇到运算符时,比较其与S1栈顶运算符的优先级:
/*
*peek():
*Looksattheobjectatthetopofthis
*stackwithoutremovingitfromthestack.
*Returntheobjectatthetopofthisstack
*(thelastitemoftheVectorobject).
*/
while(!
s1.isEmpty()&&s1.peek()!
=')'
&&priorityCompare(c,s1.peek())<0){
expression.push(s1.peek());
//乘法和除法优先级较高