Java编程之计算器
思路:计算器的实现分为三个步骤,首先是设计一个自己的栈类,然后是对表达式转为后缀表达式并计算后缀表达式,最后是计算器界面的设计。
一、定义栈
- 栈(stack):是线性表的一种,限制仅在线性表的一端进行插入和删除操作。其中允许插入和删除的一端称为栈顶(top),不允许插入和删除的一端称为栈底(bottom)。
说明:在此项目中栈主要用于将中缀表达式转为后缀表达式
具体代码如下:
public class Stack <T>{
public int front;
private int Maxsize;
private T data[];
public int lenth()//返回栈中的元素个数
{
return front+1;
}
public Stack(int size)
{
this.Maxsize=size;
data=(T [])new Object[Maxsize];
this.front=-1;
}
public void Push(T a)//压入数据
{
data[++front]=a;
}
public T Pop()//弹出数据
{
return data[front--];
}
public T getTop() {//获取栈顶元素
return data[front];
}
public boolean isEmpty()//判断栈是否为空
{
if(front==-1)
return true;
else return false;
}
}
二、将中缀表达式转为后缀表达式,并计算后缀表达式
- 中缀转后缀的方法
中缀表达式便于人们的理解与计算,但是后缀表达式更方便计算机的运算(如二叉树、堆栈的方法计算)
中缀表达式就是我们正常使用的那种,例如:1+3*2
后缀表达式就是123*+;
中缀表达式转后缀表达式的方法很多,大家可以自行去了解,此处只讲解一种
基于堆栈的算法
从左到右扫描每一个字符。如果扫描到的字符是操作数,就直接输出这些操作数
如果扫描到的字符是一个操作符,分三种情况:
(1)如果堆栈是空的,直接将操作符存储到堆栈中(push it)
(2)如果该操作符的优先级大于堆栈出口的操作符,就直接将操作符存储到堆栈中
(3)如果该操作符的优先级低于堆栈出口的操作符,就将堆栈出口的操作符导出, 直到该操作符的优先级大于堆栈顶端的操作符。将扫描到的操作符导入到堆栈中。
如果遇到的操作符是左括号"(”,就直接将该操作符输出到堆栈当中。该操作符只有在遇到右括号“)”的时候移除。这是一个特殊符号该特殊处理。
如果扫描到的操作符是右括号“)”,将堆栈中的数据出栈,直到遇见左括号“(”。将堆栈中的左括号移出堆栈。继续扫描下一个字符
如果输入的中缀表达式已经扫描完了,但是堆栈中仍然存在操作符的时候,将栈中的数据依次出栈
2.后缀表达式的计算
从左往右依次扫描后缀表达式(定义一个数组num(也可以用栈)用于存储计算结果)
(1)如果是数字,那么直接入栈到num中
(2)如果是运算符,将栈顶的两个数字出栈,出栈后对两个数字进行相应的运算,并将运算结果入栈
注意:在此项目中由于得到的后缀表达式是一个字符串,在计算后缀表达式时要将字符型的操作数数据转为整形数据。在中缀表达式转后缀表达式时,为了方便对后缀表达式的操作
用‘#’将操作数和操作符分隔开。
public class Turnexpression {
private Stack<Character> s1=new Stack<Character>(50);
//private Stack<Character> s3=new Stack<Character>(50);
private Stack<Character> s4=new Stack<Character>(50);
//private Stack<Integer> s2=new Stack<Integer>(50);
//private Queue<Character> que=new LinkedList<Character>();
private String in;
protected String output="";
public Turnexpression()
{
}
public float totrans() {//计算后缀表达式
float flo[] = new float[50];
int valuetop = 0;
String ji="";int ko=s4.lenth();String yu="";
while (!s4.isEmpty())
{
ji+=s4.Pop();
}//System.out.println(ji);
char mt[]=ji.toCharArray();
for(int k=ji.length()-1;k>=0;k--)
yu+=mt[k];
//System.out.println(yu);
float num=0;String temp="";int i;
for(i=0;i<yu.length();) {
char ch = yu.charAt(i);
if(Character.isDigit(ch)||ch=='.')
{
//System.out.println(ch);
while (Character.isDigit(ch)||ch=='.'){
temp+=ch;
ch=yu.charAt(++i);
// System.out.println("ddw");
}
num=Float.parseFloat(temp);
temp="";
flo[valuetop++]=num;
}else
{
if(ch==43)//这里的数字代表运算符的ASCLL码
{
float tem=flo[valuetop-2]+flo[valuetop-1];
valuetop--;
flo[valuetop-1]=tem;
i++;
}
if(ch==45)
{
float tem=flo[valuetop-2]-flo[valuetop-1];
valuetop--;
flo[valuetop-1]=tem; i++;
}
if(ch==42)
{
float tem=flo[valuetop-2]*flo[valuetop-1];
valuetop--;
flo[valuetop-1]=tem;i++;
}
if(ch==94)//幂运算
{
float tem=(float) Math.pow(flo[valuetop-2],flo[valuetop-1]);
//float tem=flo[valuetop-2]*flo[valuetop-1];
valuetop--;
flo[valuetop-1]=tem; i++;
}
if(ch==37)
{
float tem=flo[valuetop-2]%flo[valuetop-1];
valuetop--;
flo[valuetop-1]=tem;i++;
}
if(ch==47)
{
//System.out.println(valuetop);
float tem=flo[valuetop-2]/flo[valuetop-1];
valuetop--;
flo[valuetop-1]=tem; i++;
}
if(ch=='#')
i++;
}
}//System.out.println("ds"+flo[valuetop-1]);
if(valuetop-1==-1)
return 0;
else
// System.out.println(flo[valuetop-1]);
return flo[valuetop-1];
}
public void SetString(String in)
{
this.in=in;
}
public String doTrans() {//将中缀表达式转后缀表达式
for (int j = 0; j < in.length(); j++) {
char ch = in.charAt(j);
int n=in.length();
if(j>0&&!Character.isDigit(in.charAt(j-1))&&ch>=48&&ch<58&&in.charAt(j-1)!='.')
s4.Push('#');
//if(!Character.isDigit(in.charAt(j+1))/*in.charAt(j+1)=='+'||in.charAt(j+1)=='-'||in.charAt(j+1)=='*'||in.charAt(j+1)=='/'||in.charAt(j+1)=='%'
// ||in.charAt(j+1)=='^'||in.charAt(j+1)=='('||in.charAt(j+1)==')'*/&&(j+2)<in.length())
switch (ch) {
case '+':
case '-':
gotOper(ch, 1);
break;
case '^':
gotOper(ch, 3);
break;
case '*':
case '/':
case '%':
gotOper(ch, 2);
break;
case '(':
s1.Push(ch);
break;
case ')':
gotParen(ch);
break;
default:
{
output = output + ch;
// System.out.println("ch"+ch);
s4.Push(ch);
if(j + 1 < n && (in.charAt(j+1)=='+'||in.charAt(j+1)=='-'||in.charAt(j+1)=='*'
||in.charAt(j+1)=='/'||in.charAt(j+1)=='%'
||in.charAt(j+1)=='^'||in.charAt(j+1)==')'||in.charAt(j+1)=='(')|| j + 1 == n)
s4.Push('#');
//System.out.println("ch"+s4.Pop());
// System.out.println("ch"+s4.getTop());
}
break;
}
}
while (!s1.isEmpty()) {
// s2.Push(s1.Pop());
char k=s1.Pop();
output = output + k;
s4.Push(k);
}
return output;
}
public void gotOper(char opThis, int prec1) {//在中缀转后缀过程中对表达式的具体操作
while (!s1.isEmpty()){
char opTop = s1.Pop();
if (opTop == '(') {
s1.Push(opTop);
break;
}
else {
int prec2=0;
if (opTop == '+' || opTop == '-')
prec2 = 1;
else if(opTop == '/' || opTop == '*'||opTop == '%')
prec2 = 2;
else if(opTop=='^')
prec2=3;
if (prec2 < prec1) {
s1.Push(opTop);
break;
}
else
{output = output + opTop;
s4.Push(opTop);
}
}
}
s1.Push(opThis);
}
public void gotParen(char ch){//在转后缀表达式时处理遇到‘)’的情况
while (!s1.isEmpty()) {
char chx = s1.Pop();
if (chx == '(')
break;
else
{ output = output + chx;
s4.Push(chx);
}
}
}
public int Judje(String kn)//用于输入的判断表达式是否正确
{
char str[]=kn.toCharArray();
int l=kn.length();
if(str[0]=='-'||str[0]=='+'||str[0]=='*'||str[0]=='/'||str[0]=='%'||str[0]=='^'||str[0]=='.'||str[0]==')')
return 1;
if(str[l-1]=='+'||str[l-1]=='-'||str[l-1]=='*'||str[l-1]=='/'||str[l-1]=='%'||str[l-1]=='^'
||str[l-1]=='.'||str[l-1]=='(')
return 2;
for(int i=1;i<kn.length()-1;i++)
{
if(str[i]=='/'&&str[i+1]=='0')
return 5;
}
// System.out.println("第2");
boolean tip=true;boolean tip2=true;
for(int i=1;i<kn.length()-1;i++)
{
// System.out.println(str[i]);
if((str[i]=='.'||str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='%'||str[i]=='^')
&&!((Character.isDigit(str[i-1])&&Character.isDigit(str[i+1]))||(str[i-1]=='('||str[i-1]==')')||
(str[i+1]=='('||str[i+1]==')')))
tip=false;
//else tip=false;
//System.out.println("tip"+tip);
}
if(!tip)
return 3;
int A1=0,A2=0;
for(int i=0;i<kn.length();i++)
{
if(str[i]=='(')
A1++;
else if(str[i]==')')
A2++;
}//System.out.println("第3");
if(A1!=A2) tip2=false;
// {//System.out.println("tip:"+tip+" "+"tip2:"+tip2);
if (!tip2)return 4;//}
return 9;
}
三、界面设计(GUI编程)
界面功能:
- 获取用户输入的表达式
- 调用Turnexpression类(将中缀表达式转为后缀表达式,并计算后缀表达式)的对象中的方法对表达式进行计算
- 显示计算结果
界面成果如下:
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Interface extends JFrame implements ActionListener {
private JTextField t1;
private Turnexpression turnexpression = new Turnexpression();
public void computer() {
JFrame f1 = new JFrame("计算器"); //创建顶层容器(窗口)
f1.setLocation(200, 300);
f1.setSize(300, 350); //设置窗口大小
f1.setResizable(false);
JPanel p1 = new JPanel(new BorderLayout(5, 5)); //创建一个面板
//里面的new BorderLayout(5,5)是设置面板的布局(边框布局)
//其中(5,5)的第1个5表示上下控件间距,第2个表示左右控件间距
p1.setBorder(new EmptyBorder(5, 5, 5, 5)); //设置边界距离 border 边界
//面板的setBorder函数,用于设置面板边缘向内收缩宽度
//里面的EmtyBorder(5,5,5,5)表示面板上,左,下,右各向内收缩 5个像素
t1 = new JTextField(); //创建一个单行文本框
t1.setFont(new Font("宋体",Font.BOLD,17));
t1.setColumns(20); //这个用于设置文本框的列数 Columns 列
t1.setHorizontalAlignment(SwingConstants.LEFT); //设置文本框右对齐
//Horizontal 水平的 Alignment 对齐
JPanel p2 = new JPanel(new GridLayout(5, 5, 5, 5));//创建第二个面板
//其中设置其布局为网格布局,(第一个4表示1行4个控件)
//第2个4表示1列4个控件,第1个5表示上下控件间隔为5,第2个5表示左右控件间隔为5(像素)
JButton b1 = new JButton("7"); //创建16个按钮
b1.addActionListener(this);//注册
JButton b2 = new JButton("8");
b2.addActionListener(this);
JButton b3 = new JButton("9");
b3.addActionListener(this);
JButton b4 = new JButton("/");
b4.addActionListener(this);
JButton k1=new JButton("^");k1.addActionListener(this);
JButton k2=new JButton("(");k2.addActionListener(this);
JButton k3=new JButton(")");k3.addActionListener(this);
JButton k4=new JButton("%");k4.addActionListener(this);
p2.add(k1);
p2.add(k2);
p2.add(k3);
p2.add(k4);
JButton b5 = new JButton("4");
b5.addActionListener(this);
JButton b6 = new JButton("5");
b6.addActionListener(this);
JButton b7 = new JButton("6");
b7.addActionListener(this);
JButton b8 = new JButton("*");
b8.addActionListener(this);
JButton b9 = new JButton("1");
b9.addActionListener(this);
JButton b10 = new JButton("2");
b10.addActionListener(this);
JButton b11 = new JButton("3");
b11.addActionListener(this);
JButton b12 = new JButton("-");
b12.addActionListener(this);
JButton b13 = new JButton("0");
b13.addActionListener(this);
JButton b14 = new JButton(".");
b14.addActionListener(this);
JButton b15 = new JButton("=");
b15.addActionListener(this);
JButton b16 = new JButton("+");
b16.addActionListener(this);
p2.add(b1); //将16个按钮全部添加到网格布局的面板p2中
p2.add(b2);
p2.add(b3);
p2.add(b4);
p2.add(b5);
p2.add(b6);
p2.add(b7);
p2.add(b8);
p2.add(b9);
p2.add(b10);
p2.add(b11);
p2.add(b12);
p2.add(b13);
p2.add(b14);
p2.add(b15);
p2.add(b16);
JButton dele = new JButton("《");
dele.addActionListener(this);
JPanel p3 = new JPanel(); //创建第三个面板,用于保存之前的文本框t1
p3.add(t1, BorderLayout.NORTH); //将文本框t1添加到面板p3中
p3.add(dele, BorderLayout.EAST);
p1.add(p3, BorderLayout.NORTH);//将p3添加到 为边框布局面板的p1的北部
p1.add(p2, BorderLayout.CENTER); //将p2添加到面板的中部
f1.add(p1); //p1面板添加到窗口
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭时操作
f1.setVisible(true); //设置可见
}
@Override
public void actionPerformed(ActionEvent event) {
Object soure = ((JButton) (event.getSource())).getText();//获取按钮文字
//System.out.println(soure);
if (soure == "1") {
//System.out.println(soure);
t1.setText(t1.getText() + "1");
} else if (soure == "《") {
String sf="";
sf=t1.getText();String df="";
if(!sf.isEmpty()){
//System.out.println(sf);
df=sf.substring(0,sf.length()-1);
t1.setText(df);}else t1.setText("");
} else if (soure == "%") {
//System.out.println(soure);
t1.setText(t1.getText()+"%");
}else if (soure == "^") {
//System.out.println(soure);
t1.setText(t1.getText() +"^");
}else if (soure == ")") {
//System.out.println(soure);
t1.setText(t1.getText() +")");
} else if (soure == "(") {
//System.out.println(soure);
t1.setText(t1.getText() +"(");
} else if (soure == ".") {
//System.out.println(soure);
t1.setText(t1.getText() + ".");
} else if (soure == "2") {
//System.out.println(soure);
t1.setText(t1.getText() + "2");
} else if (soure == "3") {
//System.out.println(soure);
t1.setText(t1.getText() + "3");
} else if (soure == "4") {
//System.out.println(soure);
t1.setText( t1.getText() + "4");
} else if (soure == "5") {
//System.out.println(soure);
t1.setText(t1.getText() + "5");
} else if (soure == "6") {
//System.out.println(soure);
t1.setText(t1.getText() + "6");
} else if (soure == "7") {
//System.out.println(soure);
t1.setText(t1.getText() + "7");
} else if (soure == "8") {
//System.out.println(soure);
t1.setText(t1.getText() + "8");
} else if (soure == "9") {
//System.out.println(soure);
t1.setText(t1.getText() + "9");
} else if (soure == "0") {
//System.out.println(soure);
t1.setText(t1.getText() + "0");
} else if (soure == "+") {
//System.out.println(soure);
t1.setText(t1.getText() + "+");
} else if (soure == "-") {
//System.out.println(soure);
t1.setText(t1.getText() + "-");
} else if (soure == "*") {
//System.out.println(soure);
t1.setText(t1.getText() + "*");
} else if (soure == "/") {
//System.out.println(soure);
t1.setText(t1.getText() + "/");
} else if (soure == "=") {
String ui=t1.getText();
char yu=ui.charAt(0); //StringBuffer sd;
String gh="";
if(yu=='-')
{
// System.out.println("fdsf");
StringBuffer sd=new StringBuffer(ui);
if(yu=='('&&ui.charAt(1)=='-')
sd.insert(1,'0');
else if(yu=='-')
sd.insert(0,'0');
gh=sd.toString();
turnexpression.SetString(gh);
if(turnexpression.Judje(gh)==1)
JOptionPane.showMessageDialog(null, "表达式开头错误,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(gh)==2)
JOptionPane.showMessageDialog(null, "表达式结尾错误,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(gh)==3)
JOptionPane.showMessageDialog(null, "表达式运算符两边应为数字,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(gh)==4)
JOptionPane.showMessageDialog(null, "表达式括号不匹配,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(gh)==5)
JOptionPane.showMessageDialog(null, "除数不能为零,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else {
String uot= turnexpression.doTrans();
System.out.println("后缀表达式:"+uot);
float tr=turnexpression.totrans();
t1.setText(t1.getText()+"="+tr);}
}else {
// gh=sd.toString();
StringBuffer sdh=new StringBuffer(ui);
String op="";
boolean ght=true;
String kl=t1.getText();
for(int k=0;k<sdh.length();k++)
{
char yui=sdh.charAt(k);
if(k+1<sdh.length()&&yui=='('&&ui.charAt(k+1)=='-')
{
sdh.insert(k+1,'0');
ght=false;
}
}System.out.println(op);
op=sdh.toString();
if(!ght)
{
turnexpression.SetString(op);
//turnexpression.totrans();
if(turnexpression.Judje(op)==1)
JOptionPane.showMessageDialog(null, "表达式开头错误,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(op)==2)
JOptionPane.showMessageDialog(null, "表达式结尾错误,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(op)==3)
JOptionPane.showMessageDialog(null, "表达式运算符两边应为数字,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(op)==4)
JOptionPane.showMessageDialog(null, "表达式括号不匹配,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(op)==5)
JOptionPane.showMessageDialog(null, "除数不能为零,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else {
String uot= turnexpression.doTrans();
System.out.println("后缀表达式:"+uot);
float tr=turnexpression.totrans();
t1.setText(t1.getText()+"="+tr);}
}else
{
turnexpression.SetString(t1.getText());
//turnexpression.totrans();
if(turnexpression.Judje(t1.getText())==1)
JOptionPane.showMessageDialog(null, "表达式开头错误,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(t1.getText())==2)
JOptionPane.showMessageDialog(null, "表达式结尾错误,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(t1.getText())==3)
JOptionPane.showMessageDialog(null, "表达式运算符两边应为数字,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(t1.getText())==4)
JOptionPane.showMessageDialog(null, "表达式括号不匹配,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else if(turnexpression.Judje(t1.getText())==5)
JOptionPane.showMessageDialog(null, "除数不能为零,请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
else {
String uot= turnexpression.doTrans();
System.out.println("后缀表达式:"+uot);
float tr=turnexpression.totrans();
t1.setText(t1.getText()+"="+tr);}}}
}
}
public static void main(String[] args) {
Interface t = new Interface();
t.computer();
}
}