数据结构与算法之Stack(栈)的应用——用stack实现一个计算器——in dart

      本文用stack实现了一个计算器,支持括号、小数、负数。代码比较简单,没加什么注释。实际使用时,读取用户在stdin的输入,然后计算。若格式错误,会抛出异常。

      在实际计算过程中,实际分为三步:

  • 消除输入的空格;
  • 表达式预处理和预计算,这一步将表达式字符串解析为数字、操作符和括号。如果是括号的话,在预处理过程中会首先计算括号中的结果;因此在此步会消掉所有的括号;
  • 计算。最后这步计算,已经是比较简单的四则运算了。

      本代码有对应的bin/calc.dart 入口,并且使用了最新版的stack实现。后续文章会贴出来。或者可以到我的github上看:

https://github.com/Buerkut/data_struct

代码如下:

 1 import 'package:data_struct/stack/stack.dart';
 2 
 3 num calc(String ins) {
 4   try {
 5     var es = _preCalc(_eliminateSpace(ins));
 6     return _calc(es);
 7   } catch (e) {
 8     throw FormatException();
 9   }
10 }
11 
12 String _eliminateSpace(String ins) => ins.replaceAll(RegExp(r'\s+'), '');
13 
14 Stack<String> _preCalc(String ins) {
15   var es = Stack<String>();
16   for (var i = ins.length - 1; i >= 0; i--) {
17     if (_isDigit(ins[i])) {
18       var j = i--;
19       while (i >= 0 && _isDigit(ins[i])) i--;
20       if (ins[i] == '-' && (i == 0 || ins[i - 1] == '(')) {
21         es.push(ins.substring(i, j + 1));
22       } else {
23         es.push(ins.substring(++i, j + 1));
24       }
25     } else if (ins[i] == '(') {
26       var a = _calc(es);
27       es
28         ..pop()
29         ..push(a.toString());
30     } else {
31       es.push(ins[i]);
32     }
33   }
34   return es;
35 }
36 
37 num _calc(Stack<String> es) {
38   num a = _d(es.pop());
39   while (es.isNotEmpty && es.top != ')') {
40     var op = es.pop();
41     var b = _d(es.pop());
42     if ((op == '+' || op == '-') &&
43         es.isNotEmpty &&
44         (es.top == '*' || es.top == '/')) {
45       while (es.isNotEmpty && (es.top == '*' || es.top == '/')) {
46         var prop = es.pop();
47         var c = _d(es.pop());
48         b = prop == '*' ? b * c : b / c;
49       }
50     }
51     switch (op) {
52       case '+':
53         a += b;
54         break;
55       case '-':
56         a -= b;
57         break;
58       case '*':
59         a *= b;
60         break;
61       case '/':
62         a /= b;
63         break;
64       default:
65         break;
66     }
67   }
68   return a;
69 }
70 
71 num _d(String s) => num.parse(s);
72 
73 bool _isDigit(String c) =>
74     (c.codeUnitAt(0) >= 48 && c.codeUnitAt(0) <= 57) || c.codeUnitAt(0) == 46;

 

posted on 2019-01-15 16:49  Burkut  阅读(881)  评论(0编辑  收藏  举报