一、问题描述及基本要求
【问题描述】
设计一个简单的算术表达式计算器。
【基本要求】
实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入).
【测试数据】
(30+2*70)/3-12*3
5+(9*(62-37)+15)*6
要求自行设计非法表达式,进行程序测试,以保证程序的稳定运行。
【实现提示】
可以设计以下辅助函数
status isNumber(char ReadInChar);//视ReadInchar 是否是数字而返回 TRUE 或 FALSE 。
int TurnToInteger(char IntChar); // 将字符’0’.’9’ 转换为整数 9
二、问题分析和任务定义
1. 以字符列的形式从终端输入语法正确的、不含变量的整数表达式。利用已知的算符优先关系,实现对算术四则混合运算表达式的求值,并仿照教科书的例子在求值中运算符栈、运算数栈、输入字符和主要操作的变化过程。
2. 一般来说,计算机解决一个具体问题时,需要经过几个步骤:首先要从具体问题抽象出一个适当的数学模型,然后设计一个解决此数学模型的算法,最后编出程序,进行测试,调试直至得到想要的答案。对于算术表达式这个程序,主要利用栈,把运算的先后步骤进行分析并实现简单的运算!为实现算符优先算法,可以使用两个栈,一个用以寄存运算符,另一个用以寄存操作数和运算结果。
3. 演示程序是以用户于计算机的对话方式执行,这需要一个模块来完成使用者与计算机语言的转化。
4. 程序执行时的命令:本程序为了使用具体,采用菜单式的方式来完成程序的演示,几乎不用输入什么特殊的命令,只需按提示输入表达式即可。(要注意输入时格式,否者可能会引起一些错误)
5. 测试数据。
三、实验代码
package E3;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
//System.out.println(s.substring(1));
calculate(s);
}
//负数的问题
public static int calculate(String strExpression)
{
String s = simplify(strExpression);
System.out.println("s : "+s);
String numStr = "";//记录数字
Stack<Character> opeStack = new Stack<>();//符号站
int l = s.length();//字符串长度 l
List<String> list = new ArrayList<>();
for(int i=0;i<l;i++)
{
char ch = s.charAt(i);
if(isAllOpe(ch))
{
if(numStr!="")
{
list.add(numStr);
numStr="";
}
if(ch=='(')
{
opeStack.push(ch);
}
else if(isOpe(ch))
{
char top = opeStack.peek();
if(isGreater(ch, top))
// ch优先级大于top 压栈
{
opeStack.push(ch);
}
else
//否则,将栈内元素出栈,直到遇见 '(' 然后将ch压栈
{
while(true)
//必须先判断一下 后出栈 否则会有空栈异常
{
char t=opeStack.peek();
if(t=='(')
break;
if(isGreater(ch, t))
break;
list.add(Character.toString(t));
t=opeStack.pop();
}
opeStack.push(ch);
}
}
else if(ch==')')
{
char t = opeStack.pop();
while(t!='('&&!opeStack.isEmpty())
{
list.add(Character.toString(t));
t = opeStack.pop();
}
}
}
else//处理数字
{
numStr+=ch;
}
}
//计算后缀表达式
System.out.println(list.toString());
Stack<Integer> num = new Stack<>();
int size = list.size();
for(int i=0;i<size;i++)
{
String t =list.get(i);
if(isNumeric(t))
{//将t转换成int 方便计算
num.push(Integer.parseInt(t));
}
else
{
//如果t为运算符则 只有一位
char c = t.charAt(0);
int b = num.pop();
//如果有 算式是类似于 -8-8 这样的需要判断一下栈是否为空
int a = num.pop();
switch(c)
{
case '+':
num.push(a+b);
break;
case '-':
num.push(a-b);
break;
case '*':
num.push(a*b);
break;
case '/':
num.push(a/b);
break;
default:
break;
}
}
}
System.out.println(num.pop());
return 0;
}
/**化简表达式
* 将表达式中的 {}[]替换为()
* 负数的处理
* 为了方便将中缀转换为后缀在字符串前后分别加上(,) eg:"1+1" 变为"(1+1)"
* @param str 输入的字符串
* @return s 返回简化完的表达式
*/
public static String simplify(String str)
{
//负数的处理
// 处理负数,这里在-前面的位置加入一个0,如-4变为0-4,
// 细节:注意-开头的地方前面一定不能是数字或者反括号,如9-0,(3-4)-5,这里地方是不能加0的
// 它的后面可以是数字或者正括号,如-9=>0-9, -(3*3)=>0-(3*3)
String s = str.replaceAll("(?<![0-9)}\\]])(?=-[0-9({\\[])", "0");
//将表达式中的 {}[]替换为()
s = s.replace('[', '(');
s = s.replace('{', '(');
s = s.replace(']', ')');
s = s.replace(']', ')');
//为了方便将中缀转换为后缀在字符串前后分别加上(,)
s="("+s+")";
return s ;
}
/**判断字符c是否为合理的运算符
*
* @param c
* @return
*/
public static boolean isOpe(char c)
{
if(c=='+'||c=='-'||c=='*'||c=='/')
return true;
else
return false;
}
public static boolean isAllOpe(char c)
{
if(c=='+'||c=='-'||c=='*'||c=='/')
return true;
else if(c=='('||c==')')
return true;
else
return false;
}
/**
* 比较字符等级a是否大于b
* @param a
* @param b
* @return 大于返回true 小于等于返回false
*/
public static boolean isGreater(char a,char b)
{
int a1 = getLevel(a);
int b1 = getLevel(b);
if(a1>b1)
return true;
else
return false;
}
/**
* 得到一个字符的优先级
* @param a
* @return
*/
public static int getLevel(char a)
{
if(a=='+')
return 0;
else if(a=='-')
return 1;
else if(a=='*')
return 3;
else if(a=='/')
return 4;
else
return -1;
}
//判断是不是数字
public static boolean isNumeric(String str){
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(str);
if( !isNum.matches() ){
return false;
}
return true;
}
}