第一次发博客哈,如有问题请多多指教~~
简单介绍一下此计算器:
计算器采用中缀表达式(正常书写的表达式),可计算小数,多位数,负数,以及带括号的运算
含有去除空白等符号的功能
主要介绍一下实现的思路:
1)先输入一个中缀表达式,不带空格,可使用正则表达式去除多余干扰(如空格)
2) 定义变量,对表达式进行遍历
3)对表达式进行遍历,遍历为数字和符号两种情况(括号单说)。数字(多位数)(小数)进行字符串拼接,最后转化为数字;符号比较优先级,进行相应操作(代码中有注释)(下图中因考虑到从左到右计算原则,3.2小于或等于改为小于)
4)如果是括号,'('直接压入栈,')'则计算栈中数据,直到'(',将其弹出。计算思路如图4
5)遍历结束,输出最后值,这个值就是数栈中剩的一个值
代码可以使用自带Stack,仅声明最后几个方法也可(pri(),isoper(),cl()),本代码使用数组模拟栈,更好理解底层思维。代码也可以申请两个栈,不用单独对字符写方法。
自定义Stack如下
//定义栈
class Astack2
{
private int num; //栈值
private double[] sk1; //存储栈值
private char[] sk2; //存储符号
private int top = -1; //存储栈顶值,默认为-1
private int top2 = -1; //存储栈顶值,默认为-1
//构造器
public Astack2(int num)
{
this.num = num;
sk1 = new double[num];
sk2 = new char[num];
}
//清除数据(到结束或者到'('处)
public void clear()
{
while(true)
{
if(ischarempty())
break;
if(peek() == '(')
{
popchar();
break;
}
double k = 0;
k = cla(pop(),pop(),popchar());
push(k);
}
}
//判断是否为空
public boolean isempty()
{
return top == -1;
}
//判断符号是否为空
public boolean ischarempty()
{
return top2 == -1;
}
//判断是否为满
public boolean isfull()
{
return top == num - 1;
}
//入栈
public void push(double i)
{
if(isfull())
{
System.out.println("栈满~~");
return;
}
top++;
sk1[top] = i;
}
//入栈(符号)
public void pushchar(char i)
{
if (isfull())
{
System.out.println("栈满~~");
return;
}
top2++;
sk2[top2] = i;
}
//查看栈顶符号
public char peek()
{
return sk2[top2];
}
//出栈
public double pop()
{
if(isempty())
{
return 0;
}
top--;
return sk1[top+1];
}
//弹出符号
public char popchar()
{
top2--;
return sk2[top2+1];
}
//返回优先级
public int pri(int a)
{
if(a == '+' || a == '-')
return 0;
if(a == '*' || a == '/')
return 1;
if(a == '(')
return -1;
return -1;
}
//判断是否为运算符
public boolean isoper(int i)
{
return i == '+' || i == '-' || i == '*' || i == '/' || i == '(' || i == ')';
}
//运算方式
public double cla(double i,double j,int k)
{
double res = 0;
switch(k)
{
case '+':
res = i + j;
break;
case '-':
res = j - i;
break;
case '*':
res = i * j;
break;
case '/':
res = j / i;
break;
default:
break;
}
return res;
}
}
完成整代码如下:
package Stack;
import java.util.Scanner;
//计算加减乘除,小数,负数,带括号
//去除空格,可使用正则表达式
public class StcakCalculator
{
public static void main(String[] args)
{
System.out.println("请输入算式:");
Scanner in = new Scanner(System.in);
String expre = in.nextLine();
// \\s+匹配任意空白字符
String express = expre.replaceAll("\\s+","");
//创建两个栈,一个存放数据,一个存放符号
Astack2 sk = new Astack2(10);
//定义遍历辅助值
int tem = 0; //遍历字符串,相当图中指针
double tem1 = 0;
double tem2 = 0;
boolean i = false; //将负数转换为正数
boolean j = false; //区分(-1+2) 和 (1-2)
double res = 0; //返回值,暂存数据
char ch; //存放扫描所得的数字
String total = ""; //多位数使用
while(true)
{
ch = express.substring(tem,tem + 1).charAt(0); //将字符串第一位转化为字符
if(ch == '-') //特判,以免第一位就是符号,如 -1+2
{
i = true;
j = true;
}
if(sk.isoper(ch)) //判断是否为符号和()
{
if(sk.ischarempty() || (sk.peek() == '(' && j)) //栈顶为(,且下一个符号为-
{
if(i) //特判符号
sk.push(0);
sk.pushchar(ch);
}
else
{
if(ch == ')')
sk.clear();
else if(ch == '(')
sk.pushchar(ch);
else if(sk.pri(ch) > sk.pri(sk.peek())) //优先级大于,直接入栈
sk.pushchar(ch);
else //优先级小于,运算
{
tem1 = sk.pop();
tem2 = sk.pop();
res = sk.cla(tem1, tem2, sk.popchar()); //计算函数
sk.push(res);
sk.pushchar(ch);
}
}
}
else //为数据
{
total += ch; //多位数,小数拼接
//如果到最后一位
if(tem >= express.length() - 1)
sk.push(Double.parseDouble(total));
else
{
if(sk.isoper(express.substring(tem + 1, tem + 2).charAt(0)))
{
sk.push(Double.parseDouble(total));
j = false;
i = false;
total = "";
}
}
}
tem++; //向后遍历
if(tem >= express.length())
break;
}
//当遍历完成后,对栈中剩存的数据和符号操作
sk.clear();
in.close();
System.out.printf("%.5f",sk.pop());
}
}
//定义栈
class Astack2
{
private int num; //栈值
private double[] sk1; //存储栈值
private char[] sk2; //存储符号
private int top = -1; //存储栈顶值,默认为-1
private int top2 = -1; //存储栈顶值,默认为-1
//构造器
public Astack2(int num)
{
this.num = num;
sk1 = new double[num];
sk2 = new char[num];
}
//清除数据(到结束或者到'('处)
public void clear()
{
while(true)
{
if(ischarempty())
break;
if(peek() == '(')
{
popchar();
break;
}
double k = 0;
k = cla(pop(),pop(),popchar());
push(k);
}
}
//判断是否为空
public boolean isempty()
{
return top == -1;
}
//判断符号是否为空
public boolean ischarempty()
{
return top2 == -1;
}
//判断是否为满
public boolean isfull()
{
return top == num - 1;
}
//入栈
public void push(double i)
{
if(isfull())
{
System.out.println("栈满~~");
return;
}
top++;
sk1[top] = i;
}
//入栈(符号)
public void pushchar(char i)
{
if (isfull())
{
System.out.println("栈满~~");
return;
}
top2++;
sk2[top2] = i;
}
//查看栈顶符号
public char peek()
{
return sk2[top2];
}
//出栈
public double pop()
{
if(isempty())
{
return 0;
}
top--;
return sk1[top+1];
}
//弹出符号
public char popchar()
{
top2--;
return sk2[top2+1];
}
//返回优先级
public int pri(int a)
{
if(a == '+' || a == '-')
return 0;
if(a == '*' || a == '/')
return 1;
if(a == '(')
return -1;
return -1;
}
//判断是否为运算符
public boolean isoper(int i)
{
return i == '+' || i == '-' || i == '*' || i == '/' || i == '(' || i == ')';
}
//运算方式
public double cla(double i,double j,int k)
{
double res = 0;
switch(k)
{
case '+':
res = i + j;
break;
case '-':
res = j - i;
break;
case '*':
res = i * j;
break;
case '/':
res = j / i;
break;
default:
break;
}
return res;
}
}
还有逆波兰表达式(思路清晰):逆波兰表达式