你可能会说:这式子是怎么得到的?不要着急,我们先分析计算机如何通过这个式子得到结果。我们前面说过一种数据结构叫做栈。我们现在就利用栈结构得出结果:
继续上述过程:
我们平时使用的算式就是中缀表达式,它与后缀表达式最根本的区别就是:带有括号,所以我们需要想办法把括号给去掉,并且不影响原本计算的顺序。下面是中缀转后缀的规则:
还是以 9+(3-1)*3+10/2 为例:
此时,栈中左右括号对应,将括号中的符号弹栈并加入到后缀表达式中
继续压栈
根据上面的分析,我们知道了:要想求出一个中缀表达式的结果,我们需要先将其转为后缀表达式,再根据后缀表达式求出结果。两次用到了栈结构,这就是为什么我要说计算器是对栈结构的应用了。
下面是我用java实现的一个简易的计算器,能够进行整数,小数,负数,大数值的四则运算,并且可以分析出一些语法错误,下面是我的代码:
public class Calculator {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String middle = scan.nextLine();
char[] mid = middle.toCharArray();
mid = cutString(mid);
List list = transferToBehind(mid);
BigDecimal comeOut = calculator(list);
System.out.println(comeOut);
}
public static BigDecimal calculator(List list){
Deque deque = new ArrayDeque<>();
Iterator it = list.iterator();
while (it.hasNext()){
Object o = it.next();
if (o.getClass() == BigDecimal.class){
deque.addFirst((BigDecimal)o);
}else if (o.getClass() == Character.class){
BigDecimal first = deque.removeFirst();
BigDecimal second = deque.remove();
BigDecimal out = null;
if ((Character)o == '+'){
out = second.add(first);
deque.addFirst(out);
}else if ((Character)o == '-'){
out = second.subtract(first);
deque.addFirst(out);
}else if ((Character)o == '*'){
out = second.multiply(first);
deque.addFirst(out);
}else if ((Character)o == '/'){
Double out2 = second.doubleValue()/first.doubleValue();
String out3 = out2.toString();
deque.addFirst(new BigDecimal(out3));
}
}
}
BigDecimal comeOut = deque.removeFirst();
return comeOut;
}
public static List transferToBehind(char[] mid){
Deque deque = new ArrayDeque<>();
List list = new ArrayList();
int len = mid.length;
int i,k=0;
for (i = 0; i < len; i++){
if ( (judgeSymbol(mid[i]) && ((i > 0 && mid[i-1] != ')') || i == 0) ) || mid[i] == ')'
&& !lastBracket(mid,i) && k != i){
if (mid[i] == '-' && (i == 0 || judgeSymbol(mid[i-1]) || judgeBrackets(mid[i-1]))){
continue;
}
String number = new String(mid).substring(k, i);
if (number.contains(")")){
while ( deque.peekFirst() != '('){
list.add(deque.removeFirst());
}
deque.removeFirst();
continue;
}
BigDecimal num = new BigDecimal(number);
list.add(num);
if (judgeSymbol(mid[i]) )
k = i + 1;
else if (mid[i] == ')'){
k = i + 2;
}
}
if (judgeNumber(mid[i]) && lastNumber(mid,i)){
String number = new String(mid).substring(i);
list.add(new BigDecimal(number));
break;
}
if (mid[i] == '('){
k++;
}
if (judgeSymbol(mid[i]) || judgeBrackets(mid[i]) ){
if (mid[i] == '*' || mid[i] == '/'){
if (!deque.isEmpty() && (deque.peekFirst() == '*' || deque.peekFirst() == '/')){
while (!deque.isEmpty() && deque.peekFirst() != '(' && deque.peekFirst() != '+'
&& deque.peekFirst() != '-'){
list.add(deque.remove());
}
}
deque.addFirst(mid[i]);
}else if (mid[i] == '+' || mid[i] == '-'){
if (deque.isEmpty()){
deque.addFirst(mid[i]);
}else if (judgeSymbol(deque.peekFirst())){
while ( !deque.isEmpty() && deque.peekFirst() != '('){
list.add(deque.removeFirst());
}
deque.addFirst(mid[i]);
}else {
deque.addFirst(mid[i]);
}
}else if (mid[i] == '('){
deque.addFirst(mid[i]);
}else if (mid[i] == ')'){
while ( deque.peekFirst() != '('){
list.add(deque.removeFirst());
}
deque.removeFirst();
}
}else {
continue;
}
}
int m = 1;
while ( !deque.isEmpty() && (deque.peekFirst() == '(' || deque.peekFirst() == ')')){
deque.removeFirst();
System.out.println("有" + m++ + "个括号不匹配");
}
if (!deque.isEmpty()) {
list.add(deque.removeFirst());
}
return list;
}
public static boolean judgeSymbol(char word){
if (word == '+' || word == '-' || word == '*' || word == '/' ){
return true;
}
return false;
}
public static boolean judgeBrackets(char word){
if (word == '(' || word == ')'){
return true;
}
return false;
}
public static boolean judgeNumber(char word){
if ( (word >= '0' && word <= '9' )|| word == '.'){
return true;
}
return false;
}
public static boolean lastNumber(char[] mid,int i){
String str = new String(mid);
String rest = str.substring(i+1);
if (rest.contains("*") || rest.contains("/") || rest.contains("+") ||rest.contains("-") ||rest.contains("(")
|| rest.contains(")") ){
return false;
}
return true;
}
public static boolean lastBracket(char[] mid, int i){
if (mid[i-1] != ')' || mid[i-2] == ')'){
return false;
}
String rest = new String(mid).substring(i);
if (rest.contains("0") || rest.contains("1") ||rest.contains("2") || rest.contains("3") || rest.contains("4") ||
rest.contains("5") ||rest.contains("6") || rest.contains("7") || rest.contains("8") || rest.contains("9")){
return false;
}
return true;
}
public static boolean judgeIllegal(char[] mid,int i){
String rest = new String(mid).substring(i);
if (!rest.contains("+") && !rest.contains("-") && !rest.contains("*") && !rest.contains("/") &&
!rest.contains("(") && !rest.contains(")") && !rest.contains("0") && !rest.contains("1") &&
!rest.contains("2") && !rest.contains("3") && !rest.contains("4") && !rest.contains("5") &&
!rest.contains("6") && !rest.contains("7") && !rest.contains("8") && !rest.contains("9")){
return true;
}
return false;
}
public static char[] cutString(char[] mid){
for (int i = 0; i < mid.length; i++){
if (!judgeBrackets(mid[i]) && !judgeSymbol(mid[i]) && !judgeNumber(mid[i])){
System.out.println("出现非法字符!已为你自动消除");
if (i == 0){
mid = Arrays.copyOfRange(mid,1,mid.length);
i--;
}else if (judgeIllegal(mid,i)){
mid = Arrays.copyOfRange(mid,0,i);
break;
}else {
char[] beyond = Arrays.copyOfRange(mid,0,i);
char[] behind = Arrays.copyOfRange(mid,i+1,mid.length);
String str1 = new String(beyond);
String str2 = new String(behind);
String temp = str1 + str2;
mid = temp.toCharArray();
i--;
}
}
}
return mid;
}
}
正常测试:
非正常测试:
暴力测试:
之所以用Java写而不用C语言写就是因为Java可以直接调用很多封装好的类和方法,这个程序用Java写了200行代码,如果用C语言写估计得600行以上。
至于四则运算太少,其他的运算也可以添加,就是要判断更多的符号优先级的问题。