JAVA实现四则运算
一、四则运算概念
四则运算是指加法、减法、乘法和除法四种运算,例如:1+(2-3/4)*5 。我们可以很快得到答案,但如何通过编程实现其运算呢?
波兰的一位叫做卢卡西维奇的逻辑学家发明了一种表示表达式的方法,称为逆波兰式,也叫后缀表达式。平时我们所看到的四则运算,都是中缀表达式,因为运算符总是处在数字的中间。计算机首先将我们常见的中缀表达式转换为后缀表达式,然后再进行运算。转换的过程如下:
-
首先初始化一个栈结构,这个栈我称为符号栈;
-
然后从左到右遍历中缀表达式,遇到数字,追加到后缀表达式中;如果遇到左括号,则将其入栈;如果遇到右括号,则执行出栈操作,依次将出栈元素追加到后缀表达式,直到出栈元素是左括号为止,左括号不追加到后缀表达式中;如果是加减乘除,就弹出最近左括号之前(没有左括号则为整个栈)所有优先级大于或者等于该运算符的栈顶元素(栈中肯定没有右括号,认为左括号的优先级最低,加减次之,最高乘除),然后将该运算符入栈;
-
遍历完中缀表达式之后,清空栈,并依次将出栈元素追加到后缀表达式中。
这样,计算机就把中缀表达式转换成了后缀表达式。然后就开始计算后缀表达式的值,过程如下:
-
同样初始化一个栈结构,或者直接使用刚才的栈;
-
遍历后缀表达式,遇到数字就入栈;遇到运算符则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再入栈,直到后缀表达式遍历完毕;
-
遍历完后缀表达式之后,栈中必然只有一个元素,就是我们要的结果了。
例如我们上面举例的1+(2-3/4)*5,流程为:将 ‘1’ 放入后缀表达式,‘+’放入符号栈,‘(’放入符号栈,'2’放入后缀表达式,‘-’放入符号栈,这里因为有左括号,所以不弹出之前的 + 号,‘3’ 放入后缀表达式,‘/’放入符号栈,‘4’放入后缀表达式,然后我们遇到 ‘)’ ,所以需要将符号栈里 ‘(’ 之后的元素依次弹出放入后缀表达式,即弹出 ‘/’ 、‘-’ ,放入后缀表达式中,然后 ‘ * ’ 入符号栈,‘5’ 放入后缀表达式,那么这里我们已经将整个字符数组遍历完毕了,然后将符号栈里的元素依次弹出加入后缀表达式,我们就得到了上式的后缀表达式:1 2 3 4 / - 5 * +
二、实现代码
//四则运算
public class FourFundamentalRules {
private static Stack<Character> stack = new Stack<>();//后缀表达式
private static Stack<Character> stack_1 = new Stack<>();//符号栈
private static Stack<Character> stack_2 = new Stack<>();//临时栈
public static void main(String[] args) {
String str = "1+(2-3/4)*5";
try {
Double b = calculate(str);
System.out.println("运算结果为:"+b);
}catch (Exception e){
System.out.println("error");
}
}
//运算
private static Double calculate(String str) throws Exception{
char[] arr = str.toCharArray();
//转化为后缀表达式
for(int i=0;i<arr.length;i++){
if(Character.isDigit(arr[i])){//判断是否为数字
stack.push(arr[i]);
}else if(arr[i] == '*'||arr[i] == '/'){
while(!stack_1.empty()){
char ch = stack_1.pop();
if(ch == '('){
stack_1.push(ch);
break;
}else if(ch == '*' || ch == '/'){
stack.push(ch);
}else{
stack_2.push(ch);
}
}
while(!stack_2.empty()){
stack_1.push(stack_2.pop());
}
stack_1.push(arr[i]);
} else if(arr[i] == '+'|| arr[i] == '-'){
while(!stack_1.empty()){
char ch = stack_1.pop();
if(ch == '('){
stack_1.push(ch);
break;
}else if(ch == '*' || ch == '/'||ch == '+'|| ch == '-'){
stack.push(ch);
}else{
stack_2.push(ch);
}
}while(!stack_2.empty()){
stack_1.push(stack_2.pop());
}
stack_1.push(arr[i]);
}else if(arr[i] == '('){
stack_1.push(arr[i]);
}else if(arr[i] == ')'){
char ch = stack_1.peek();
while(ch != '('){
ch = stack_1.pop();
stack.push(ch);
}
stack.pop();
}else{
throw new Exception();
}
}
while(!stack_1.empty()){
stack.push(stack_1.pop());
}
//进行运算
while(!stack.empty()){
stack_2.push(stack.pop());
}
Stack<Double> s = new Stack<>();//用于最后计算的栈
while(!stack_2.empty()){
char ch = stack_2.pop();
if(ch == '*' || ch == '/'||ch == '+'|| ch == '-'){
double sum = 0;
double num1= s.pop();
double num2= s.pop();
switch (ch){
case '*':sum = num2*num1;break;
case '/':sum = num2/num1;break;
case '+':sum = num2+num1;break;
case '-':sum = num2-num1;break;
}
s.push(sum);
}else if (Character.isDigit(ch)){
s.push((double)Character.getNumericValue(ch));
}else{
throw new Exception();
}
}
return s.pop();
}
}
三、小知识点总结
1. 字符串转化为字符数组
String str = "1+(2-3/4)*5";
char[] arr = str.toCharArray();
2. 判断一个char是否为数字
Character.isDigit(ch)
3. char和int类型的转换:
<1> char转化为int
使用函数
Character.getNumericValue(ch);
或者
char ch = '1';
int n =(char)(ch-'0');
<2> int转化为char
int n = 1;
char ch = (char)(n + '0');
因为double的范围比int宽所以在代码中选择强转
本文前半部分文字描述参考 jia_costa的博客
链接:https://blog.csdn.net/jia_costa/article/details/79042679