写一个函数,计算一个四则运算表达式的值。有加减乘除和括号,空格忽略。不许使用eval等直接求值的函数。

    1. function calc(str) {
    2. // TODO
    3. }
    4. calc('1 + 2 + 3') // 6
    5. calc('1+2+3') // 6
    6. calc('1+2*3') // 7
    7. calc('(1+2)*3+4') // 13
    8. 例如: 需要计算 3 * (1 + 2 ) * 5 那么先计算 1+2,我们记做 1 2 + 再计算 3 * (1 + 2) 记做 3 1 2 + * 最后计算 3 * (1 + 2 ) * 5 记做 3 1 2 + * 5 * 提示:利用栈(周六课程讲解)
    9. 然后再从左到右计算。
    10. 答案:
    11. function calc(str){
    12. const list = str.match(/(\d+|[+-\\*/()])/g)
    13. }
    14. 答案:
    15. // 定义操作符优先级
    16. const precedence = {
    17. '+' : 1,
    18. '-' : 1,
    19. '*' : 2,
    20. '/' : 2,
    21. '(' : 0,
    22. ')' : 0
    23. }
    24. // 出栈(pop stack)直到断言函数(prediction function) 返回false
    25. // 并返回最终的结果
    26. function poptill(stack, prediction) {
    27. let o = null
    28. let r = []
    29. while(o = stack.pop()) {
    30. if(!prediction(o)) {
    31. stack.push(o)
    32. break
    33. }
    34. r.push(o)
    35. }
    36. return r
    37. }
    38. // 将中缀(infix)序列转成后缀(postfix)序列,
    39. // 比如 A + B -> A B +
    40. // 再比如 A + B * C -> A B C * +
    41. // 再比如 A * (B + C) -> A B C + *
    42. // 本质上 ABC的相对顺序不变,后缀序列的操作符会在不同的地方
    43. function infix2postfix(list){
    44. // 操作符栈
    45. const opstack = []
    46. // 后缀序列结果
    47. let r = []
    48. list.forEach(c => {
    49. if(/(\+|-|\*|\/)/.test(c)) {
    50. const ops = poptill(opstack, op => precedence[op] >= precedence[c])
    51. r = r.concat(ops)
    52. opstack.push(c)
    53. }
    54. else if(c === '(') {
    55. opstack.push(c)
    56. }
    57. else if(c === ')') {
    58. const ops = poptill(opstack, op => op !== '(')
    59. opstack.pop()
    60. r = r.concat(ops)
    61. }
    62. else {
    63. r.push(c)
    64. }
    65. })
    66. opstack.reverse().forEach(x => r.push(x))
    67. return r
    68. }
    69. // 利用stack对后缀序列求值
    70. function evaluate(list) {
    71. list = list.reverse()
    72. const stack = []
    73. while(list.length > 0) {
    74. const c = list.pop()
    75. if(/(\+|-|\*|\/)/.test(c)) {
    76. const o1 = Number(stack.pop())
    77. const o2 = Number(stack.pop())
    78. switch(c) {
    79. case '+' :
    80. stack.push(o1 + o2)
    81. break
    82. case '-' :
    83. stack.push(o1 - o2)
    84. break
    85. case '*' :
    86. stack.push(o1 * o2)
    87. break
    88. case '/' :
    89. stack.push(o1 / o2)
    90. break
    91. }
    92. }
    93. else {
    94. stack.push(c)
    95. }
    96. }
    97. return stack[0]
    98. }
    99. function calc(str) {
    100. const list = str.match(/(\d+|\+|-|\*|\/|[()])/g)
    101. const postfixs = infix2postfix(list)
    102. return evaluate(postfixs)
    103. }