求一个包加减乘除和小括号的字符串的结果

解题思路和代码原型来源于牛课网, 我自己实现了一遍,添加了部分注释

 

  1 package problems_2016_08_10;
  2 
  3 import java.util.LinkedList;
  4 /*
  5 总述:
  6 一共有五个函数分别是:
  7                     
  8                     getvalue():
  9                           参数:待求的字符串、
 10                           作用:一个启动函数,调用value函数
 11                           返回值:返回value函数返回值的第一个参数,就是求出的值
 12 
 13                     value():
 14                           参数:总的待求的字符串,从哪一个位置开始求
 15                           作用:这个函数只是可以求不加小括号的情况。
 16                                   在这种情况下,把数字和加减乘除放进que双端链表中,并且在放的时候用addnum方法,将乘除处理掉,只剩加减和数字,再将que链表通过getnum方法求出具体的值,返回给上一层。
 17                                   因为不能处理小括号,所以碰见小括号就将括号里面的内容抛给下一层递归(value函数)。
 18                                   这个value函数只有当发现右括号就停止
 19                           返回值:value函数在返回求出的结果的时候,还要返回处理的右括号的位置的索引值
 20                     addnum()
 21                           参数:que双端链表(这个是在value函数里面定义的),一个待添加进来的数字(value里面的pre)
 22                           作用:将字符串中紧挨的数字(表示是一个多位数字)转化为一个数字,并且将他加入到que中,在加入时处理掉que中的乘除号
 23                           返回值:没有返回值。因为是在value内部调用的,将当层递归的que变成了只包含加减和数字的字符
 24 
 25                     getnum()
 26                           参数:只包含加减和数字的que
 27                           作用:将只包含加减和数字的que求出结果
 28                           返回值:返回的是每一层小括号中(也是每一层递归当中)的结果
 29                     main()
 30                           用来进行检测代码功能的函数
 31                     
 32 
 33 */
 34 public class ExpressionCompute {
 35 
 36     public static int getValue(String str) {
 37         return value(str.toCharArray(), 0)[0];
 38     }
 39 
 40     public static int[] value(char[] str, int i) {
 41         LinkedList<String> que = new LinkedList<String>();
 42         int pre = 0;
 43         int[] bra = null;
 44         while (i < str.length && str[i] != ')') {//如果i(当前操作位置)还没有到达最有端,并且还没有碰到右边的括号,那就继续执行这个递归函数
 45             if (str[i] >= '0' && str[i] <= '9') {//如果当前操作的是两个运算符号之间的数字
 46                 pre = pre * 10 + str[i++] - '0';//将字符串格式的数字转换为int,减'0'相当于减了这个字符的ascii码的值,字符串就变成数字了
 47             } else if (str[i] != '(') {//如果发现也没有碰到了左括号,那说明碰到的是运算符
 48                 addNum(que, pre);//这个函数的功能是在pre加入que时看一下que的最后一个字符(肯定是运算符)是否为乘除,是的话进行结算
 49                 que.addLast(String.valueOf(str[i++]));//在上面获取到结算的结果加入之后下一位肯定是运算符,也加入
 50                 pre = 0;//把pre(用来存放两个运算符之间的数值的变量)清零
 51             } else {//说明遇到左括号里 
 52                 bra = value(str, i + 1);//碰到了左括号,那么就调用这个函数本身,将左括号之后的内容加入到内层递归中(传入的是左括号的下一个位置的索引)
 53                 pre = bra[0];//value函数返回一个数组(第29行)   第一个参数为处理过的值
 54                 i = bra[1] + 1;//第二个是处理到的值,+1表示下次开始处理的位置
 55             }
 56         }
 57         addNum(que, pre);//最后没有遇到加减乘除  所以还要再来一次addnum
 58         return new int[] { getNum(que), i };//返回这一层递归中的值和 处理到的位置i
 59     }
 60 
 61     public static void addNum(LinkedList<String> que, int num) {//这个函数的作用可以看成和que.addLast类似,que.addLast是直接把符号插入到que中需要用到的方法,当时当你想插入数字时需要看一下前一个符号的情况,所以自己封装了一个稍微复杂点儿的类似的方法
 62         if (!que.isEmpty()) {//判断是否为空
 63             int cur = 0;
 64             String top = que.pollLast();//先弹出一个
 65             if (top.equals("+") || top.equals("-")) {
 66                 que.addLast(top);//如果之前是加减,直接把这个数字放进去就可以了
 67             } else {//如果之前的符号为乘除,那需要运算之后才能放入(保证que里面始终只放加减符号和数字)
 68                 cur = Integer.valueOf(que.pollLast());//再弹出一个
 69                 num = top.equals("*") ? (cur * num) : (cur / num);//将第二次弹出的(肯定是一个数字,由19  20行可知)
 70             }
 71         }
 72         que.addLast(String.valueOf(num));//为空的话直接插入num,不为空让算出的结果等于num,好巧妙,又省了几行代码
 73     }
 74 
 75     public static int getNum(LinkedList<String> que) {//getnum的方法的作用仅仅是求一个只包含加减和数字的数组,的运算结果
 76         int res = 0;//用来保存结果
 77         boolean add = true;//用来描述一种状态,其实就是区分加减
 78         String cur = null;//用来存放每次新的pollFirst()出来的值(是string类型的)
 79         int num = 0;//用来保存cur转换回来的num类型
 80         while (!que.isEmpty()) {//判断que里面是不是空的
 81             cur = que.pollFirst();//弹出双向列表第一个
 82             if (cur.equals("+")) {//如果弹出的是加号
 83                 add = true;//将add设置为true,用于下一个检测到数字的时候使用
 84             } else if (cur.equals("-")) {//如果弹出的是减号
 85                 add = false;//将add设置为false,用于下一个检测到数字的时候使用
 86             } else {//如果不为加减那么肯定就是数字了
 87                 num = Integer.valueOf(cur);//将字符类型的准换成数字类型
 88                 res += add ? num : (-num);//res+=(+num或者-num),三目运算符大大减少代码数量
 89             }
 90         }
 91         return res;//返回最后求出的结果
 92     }
 93 
 94     public static void main(String[] args) {//进行一些测试
 95         String exp = "48*((70-65)-43)+8*1";
 96         System.out.println(getValue(exp));
 97 
 98         exp = "4*(6+78)+53-9/2+45*8";
 99         System.out.println(getValue(exp));
100 
101         exp = "10-5*3";
102         System.out.println(getValue(exp));
103 
104         exp = "-3*4";
105         System.out.println(getValue(exp));
106 
107         exp = "3+1*4";
108         System.out.println(getValue(exp));
109 
110     }
111 
112 }

 

posted @ 2016-09-02 12:07  萝卜er  阅读(969)  评论(0编辑  收藏  举报