发布于2021-03-13 14:05 阅读(884) 评论(0) 点赞(30) 收藏(3)
这个思想能够解决含有+ - * /()的表达式
步骤:
一、对表达式进行预处理,把式子中的空格去掉,把(-10)替换为(0-10);
如:String s = "1 + 10 + 5 * (-10 + 5)"
对s进行预处理
- s = s.replaceAll(" ","");
- s = s.replaceAll("\\(-", "(0-",);
- char[] chars = s.toCharArray();
得到结果 s = "1+10+5*(0-10+5)"
二、使用两个栈 stNums 和 stOps分别存放数字和操作符:
由于第一个数可能是负数,为了减少边界判断。一个小技巧是先往 stNums 添加一个 0
- // 创建一个栈来存放所有的数字
- Deque<Integer> stNums = new ArrayDeque<>();
-
- // 为了防止第一个数为负数,先往 nums 加个 0
- stNums.addLast(0);
-
- // 创建一个栈存放所有运算符
- Deque<Character> stOps = new ArrayDeque<>();
注意:为什么我们用双端队列来Deque来模拟栈呢?
因为Java堆栈Stack类已经过时,Java官方推荐使用Deque替代Stack使用。可以通过Deque的addLast()/offerLast(), removaLast()/pollLast(), getLast()/peekLast() 来达到栈后进先出的效果
三、然后从前往后进行遍历,:
- if(chars[i] >= '0' && chars[i] <= '9'){
- int num = ch - '0'; //num存储当前数字 比如出现123的情况
- while(i + 1 < len && chars[i + 1] >= '0' && chars[i + 1] <= '9'){
- num = num * 10 + (chars[i + 1] - '0');
- i++;
- }
- stNums.offerLast(num)
- }
例子 只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算 是什么意思:
因为我们是从前往后做的,假设我们当前已经扫描到 2 + 1 了(此时stNums中为: 2 1, stOps为 +)。
如果后面出现的 + 2 或者 - 1 的话,满足「栈内运算符」比「当前运算符」优先级高/同等,可以将 2 + 1 算掉,把结果放到 nums 中(此时stNums中为: 3, stOps为 );
如果后面出现的是 * 2 或者 / 1 的话,不满足「栈内运算符」比「当前运算符」优先级高/同等,这时候不能计算 2 + 1,则把* 2放入栈中(此时stNums中为: 2 1 2, stOps为 + *)。
- // 使用 map 维护一个运算符优先级
- // 这里的优先级划分按照「数学」进行划分即可,数字越高优先级越高
- Map<Character, Integer> map = new HashMap<>(){{
- put('-', 1);
- put('+', 1);
- put('*', 2);
- put('/', 2);
- put('%', 2);
- put('^', 3);
- }};
- static int calculate(String s) {
- // 将所有的空格去掉
- s = s.replaceAll(" ", "");
- //将 (- 替换为 (0-
- s = s.replaceAll("\\(-", "(0-");
- char[] chars = s.toCharArray();
- int len = s.length();
- // 创建一个栈来存放所有的数字
- Deque<Integer> stNums = new ArrayDeque<>();
- // 为了防止第一个数为负数,先往 nums 加个 0
- stNums.offerLast(0);
- // 创建一个栈存放所有运算符
- Deque<Character> stOps = new ArrayDeque<>();
- for (int i = 0; i < len; i++) {
- char ch = chars[i];
- if(ch >= '0' && ch <= '9'){
- int num = ch - '0'; //num存储当前数字 比如出现123的情况
- while(i + 1 < len && chars[i + 1] >= '0' && chars[i + 1] <= '9'){
- num = num * 10 + (chars[i + 1] - '0');
- i++;
- }
- stNums.offerLast(num);
- }
- else if (ch == '(') {
- stOps.offerLast(ch);
- }
- else if (ch == ')') {
- // 计算到最近一个左括号为止
- while (!stOps.isEmpty()) {
- if (stOps.peekLast() != '(') {
- calc(stNums, stOps);
- } else {
- stOps.pollLast();
- break;
- }
- }
- }
- else {
- // 有一个新操作要入栈时,先把栈内可以算的都算了
- // 只有满足「栈内运算符」比「当前运算符」优先级高/同等,才进行运算,直到运算完毕
- while (!stOps.isEmpty() && stOps.peekLast() != '(') {
- char prev = stOps.peekLast(); //检查stOps尾部运算符与当前运算符优先级谁高
- if (map.get(prev) >= map.get(ch)) {
- calc(stNums, stOps);
- } else {
- break;
- }
- }
- stOps.offerLast(ch);
- }
- }
- // 将剩余的计算完
- while (!stOps.isEmpty()) calc(stNums, stOps);
- return stNums.peekLast();
- }
-
- static void calc(Deque<Integer> stNums, Deque<Character> stOps) {
- if (stNums.isEmpty() || stNums.size() < 2) return; //当stNums为空或者只存一个数的时候没法运算直接返回
- if (stOps.isEmpty()) return; //当stOps为空时候没法运算直接返回
- int num2 = stNums.pollLast(), num1 = stNums.pollLast();
- char op = stOps.pollLast();
- int res = 0;
- if (op == '+') {
- res = num1 + num2;
- } else if (op == '-') {
- res = num1 - num2;
- } else if (op == '*') {
- res = num1 * num2;
- } else if (op == '/') {
- res = num1 / num2;
- } else if (op == '^') {
- res = (int)Math.pow(num1, num2);
- } else if (op == '%') {
- res = num1 % num2;
- }
- //把计算结果重现放入栈中
- stNums.offerLast(res);
- }
作者:zhqu4399
链接:http://www.javaheidong.com/blog/article/114301/3bedccad2391086407eb/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!