运用数据结构实现计算器(java语言描述)

七年前在百度空间写的文章,一字不差的贴过来~

----------------------------------------------分割线-----------------------------------------------------

大二的时候数据结构没有学好,当时用C语言没能完成的一个实验报告。今天在我熟悉java语言的情况下,重新自学数据结构与算法。下面用java语言实现了大二没有完成的实验报告,当然算法有很多需要改进的地方,需要学习别人的实现方法,而且算法里少了很多字符串合法性验证,原因很简单,我的主要目的是用数据结构的知识实现功能。

先说说我实现的思想
首先把复杂问题简单化,先考虑没有括号但是表达式是连续的情况
运算符当中‘*’和‘/’具有相同优先级而且是最高优先级,而'+'和'-'有相同优先级并次于乘除
把复杂的问题简单化,就像cpu只有加法器,所有的运算都转换为加法运算,这里我也是这样想的
首先让字符串入栈,情况如下:
我用[]表示一个元素
例如:3+2*3
[3][+][2][*][3]
栈顶出栈(在不考虑字符串不合法的情况下第一个出栈的一定是操作数)后面紧跟的是运算符
第一步:
      出栈得到数据  [3]
      栈内          [3][+][2][*]
第二步:
       出栈得运算符  [*]
       栈内    [3][+][2]
第三步:
       判断到运算符是‘*’
第四步:
       出栈得到数据  [2]
       栈内    [3][+]
第五步:
       计算    [3]*[2] = [6]
       入栈    [6]
       栈内    [3][+][6]
第六步:
       栈内元素累加的结果:3+6 = 9

现在来考虑有括号的情况:
例如:[3+(2+4*3)]
我用两个栈,第一个栈用来存放括号,第二个用来存放数
第一步:
       栈一 [[]
       栈二 [#]  #号用于标记
第二步:
       栈一 [[]
       栈而 [#][3]
第三步:
       栈一 [[]
       栈二 [#][3][+]
第四步:
       栈一 [[][(]
       栈二 [#][3][+][#]
第五步:
      栈一 [[][(]
      栈二 [#][3][+][#][2]
第六步: 
      栈一 [[][(]
      栈二 [#][3][+][#][2][+]
第七步: 
      栈一 [[][(]
      栈二 [#][3][+][#][2][+][4]
第八步: 
      栈一 [[][(]
      栈二 [#][3][+][#][2][+][4][*]
第九步:
      栈一 [[][(]
      栈二 [#][3][+][#][2][+][4][*][3]
第十步:
      由于发现括号匹配所以栈一出栈
      栈一    [[]
      以“#”号为标记得到一个连续的没有括号的运算式2+4*3  计算得到结果  14  然后再压入栈二
      栈二 [#][3][+][12]
第十一步:
      由于发现括号匹配所以栈一出栈
      栈一 空
      以“#”号为标记得到一个连续的没有括号的运算式3+12  计算得到结果  15  压入栈二
第十二步:
      发现栈一为空  计算完毕
      栈二弹出   得到结果 15

代码如下:

import java.util.*;

public class Calculator {

 public static boolean machesBrackets(String expression1, String expression2) {
  if (expression1.equals("{") && expression2.equals("}")) {
   return true;
  } else if (expression1.equals("(") && expression2.equals(")")) {
   return true;
  } else if (expression1.equals("[") && expression2.equals("]")) {
   return true;
  } else {
   return false;
  }
 }

 public static void main(String[] args) {
  Scanner input = new Scanner(System.in);
  System.out.println("请输入预算表达式");
  String expression = input.next();
  expression = "{" + expression + "}";  //这样的目的是当用户输入的表达式最外是数字而非括号时,为了每个数都能入栈,所以添加对括号在外面
  SimpleCalculator scct = new SimpleCalculator(); // 用于处理连续的没有括号的数学表达式
  Stack stack1 = new Stack(); // 用于匹配括号
  Stack stack2 = new Stack(); // 用于存储和处理操作数
  String bracket = ""; // 存储括号的临时变量
  String regex = "[({)}\\[\\]]{1}";
  String temp = "";
  stack2.push("#");// 向栈2压入标志
  for (int i = 0; i < expression.length(); i++) {
   if ((bracket = expression.charAt(i) + "").matches(regex)) { // 如果是括号
    if (!stack1.isEmpty()) {
     String bkt = stack1.getTop().toString();// 栈1弹出栈顶元素得到准备匹配的括号
     if (Calculator.machesBrackets(bkt, bracket)) {// 如果匹配成功
      stack1.pop();// 栈顶出栈
      String str = "";
      if (!stack2.isEmpty()) { // 如果栈2不为空
       String exp = "";
       List<String> tempExpression = new ArrayList<String>();
       while (!(str = stack2.pop().toString()) // 若不是结束标记
         .equals("#")) {
        tempExpression.add(str);
       }
       for (int j = tempExpression.size() - 1; j >= 0; j--) {  
        exp += tempExpression.get(j);
       }
       tempExpression = null;
       System.out.println(exp);  //调试语句
       Integer result = scct.calculate(exp); // 计算出结果
       System.out.println("result:" + result); //调试语句
       System.out.println("----------------");//调试语句
       stack2.push(result.toString()); // 将计算结果压入栈2
      }
     } else { // 如果匹配不成功
      stack1.push(bracket); // 将括 号压入栈顶
      stack2.push("#"); // 向栈2压入标志
     }
     // ds.push(stack1, expression.charAt(i) + "");
    } else {
     stack1.push(expression.charAt(i) + "");
    }
   } else { // 如果是操作数或者运算符
    temp = expression.charAt(i) + "";
    stack2.push(temp);
   }
  }
  System.out.println("The result is " + stack2.pop());
 }
}

class SimpleCalculator {

 public int calculate(String expression) {
  Stack stack1 = new Stack();
  Stack stack2 = new Stack();
  Stack tempStack = new Stack();
  String d = "";
  if (expression.charAt(0) == '-') {//如果表达式第一个是负号
   expression = "0" + expression;
  }
  for (int i = 0; i < expression.length(); i++) {
   String c = expression.charAt(i) + "";
   if (c.matches("[\\d{1}]")) {
    d += c;
   } else {
    stack1.push(d); // 运算数入栈
    stack1.push(c); // 运算符入栈
    d = "";
   }
  }
  stack1.push(d); // 最后一个操作数入栈
  int temp1 = 0; // 暂存第一个操作数
  int temp2 = 0; // 暂存第二个操作数
  String sign = ""; // 暂存操作符
  while (!stack1.isEmpty()) { // 如果栈1不为空
   temp1 = Integer.parseInt(stack1.pop().toString()); // 栈1出栈 得到第一个运算数
   sign = (String) stack1.pop(); // 栈1出栈 得到运算符
   int result = 0; // 用于存储每次运算的结果
   if (sign == null) { // 如果没有取到操作符,说明是最后一个操作数
    stack2.push(temp1);
    break;
   } else if (sign.equals("*")) { // 如果为乘法
    temp2 = Integer.parseInt(stack1.pop().toString());// 栈1出栈
    // 得到第二个操作数
    result = temp1 * temp2;
    stack1.push(result); // 将预算结果压入栈1
   } else if (sign.equals("/")) { // 如果为除法
    temp2 = Integer.parseInt(stack1.pop().toString());// 栈1出栈
    // 得到第二个操作数
    tempStack.push(temp1);
    tempStack.push(temp2);
    while (!stack1.isEmpty() && stack1.getTop().equals("/")) {
     stack1.pop();  //运算符出栈
     tempStack.push(stack1.pop());  //运算数出栈,并压入临时栈
    }
    result = Integer.parseInt(tempStack.pop().toString());
    while (!tempStack.isEmpty()) {
     temp1 = Integer.parseInt(tempStack.pop().toString());
     result = result / temp1;
    }
    stack1.push(result); // 将预算结果压入栈1
   } else if (sign.equals("-")) { // 如果为加减法
    temp1 = -temp1;
    stack2.push(temp1);
   } else { // 如果是加法
    stack2.push(temp1);
   }
  }
  // 现在栈2的操作数全部是加法的操作数,那么只要对栈2的操作数累加即可得到运算结果
  int result = 0;
  while (!stack2.isEmpty()) {
   Integer temp = (Integer) stack2.pop();
   result += temp;
  }
  return result;
 }
}

class Stack {
 
 List<Object> ls = new ArrayList<Object>();
 
 public Object pop() { // 出栈
  if (!this.isEmpty()) {
   Object data = ls.get(ls.size() - 1);
   ls.remove(ls.size() - 1);
   return data;
  }
  return null; // 如果栈为空
 }

 public void push(Object data) { // 压栈
  ls.add(data);
 }

 public Object getTop() { // 获取栈顶元素
  if (!this.isEmpty()) {
   return ls.get(ls.size() - 1);
  }
  return null; // 如果栈为空
 }

 public boolean isEmpty() { // 判断栈是否为空
  if (ls.size() == 0) {
   return true;
  }
  return false;
 }
}

输入:[3*2+(5*3*(3+2*3))-5]/2

结果:

3+2*3
result:9
----------------
5*3*9
result:135
----------------
3*2+135-5
result:136
----------------
136/2
result:68
----------------
The result is 68

这个程序稳定性先不说,因为主要矛盾不是这个,我们的目的是学习数据结构。但是我觉得该算法肯定有很多不好的地方,我很希望有人能指出来,并给予指点!

转载于:https://my.oschina.net/xiaoshushu/blog/1589404

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值