需求

输入一个表达式,返回计算结果。比如: 3 + 2 * 6 - 2 = 13
按照运算符的优先级进行正确的运算

思路

image.png

代码

  1. // 栈的运用 - 计算表达式
  2. package main
  3. import (
  4. "errors"
  5. "fmt"
  6. "strconv"
  7. )
  8. type Stack struct {
  9. MaxTop int // 栈的容量
  10. Top int // 栈顶下标 默认 -1
  11. arr [20]int // 数组模拟栈
  12. }
  13. // 入栈
  14. func (stack *Stack) Push(val int) (err error) {
  15. // 栈满
  16. if stack.Top == stack.MaxTop-1 {
  17. fmt.Println("stack full")
  18. return errors.New("stack full")
  19. }
  20. stack.Top++
  21. // 放入数据
  22. stack.arr[stack.Top] = val
  23. return
  24. }
  25. // 出栈
  26. func (stack *Stack) Pop() (val int, err error) {
  27. if stack.Top == -1 {
  28. fmt.Println("空栈")
  29. return 0, errors.New("空栈")
  30. }
  31. // 取出数据
  32. val = stack.arr[stack.Top]
  33. stack.Top--
  34. return val, nil
  35. }
  36. // 遍历栈
  37. func (stack *Stack) List() {
  38. if stack.Top == -1 {
  39. fmt.Println("空栈")
  40. return
  41. }
  42. for i := stack.Top; i >= 0; i-- {
  43. fmt.Printf("arr[%d] = %v \n", i, stack.arr[i])
  44. }
  45. }
  46. // 判断是运算符的函数 + - * / , 利用 ASCII 码
  47. func (stack *Stack) IsOper(val int) bool {
  48. if val == 42 || val == 43 || val == 45 || val == 47 {
  49. return true
  50. } else {
  51. return false
  52. }
  53. }
  54. // 运算的方法
  55. func (stack *Stack) Cal(num1 int, num2 int, oper int) int {
  56. // 注意运算的顺序
  57. res := 0
  58. switch oper {
  59. case 42:
  60. res = num2 * num1
  61. case 43:
  62. res = num2 + num1
  63. case 45:
  64. res = num2 - num1
  65. case 47:
  66. res = num2 / num1
  67. default:
  68. fmt.Println("运算符错误")
  69. }
  70. return res
  71. }
  72. // 返回运算符的优先级: * / => 1 ; + - => 0
  73. func (stack *Stack) Priority(oper int) int {
  74. res := 0
  75. if oper == 42 || oper == 47 {
  76. res = 1
  77. } else if oper == 43 || oper == 45 {
  78. res = 0
  79. }
  80. return res
  81. }
  82. func main() {
  83. // 数栈
  84. numStack := &Stack{
  85. MaxTop: 20,
  86. Top: -1,
  87. }
  88. // 符号栈
  89. operStack := &Stack{
  90. MaxTop: 20,
  91. Top: -1,
  92. }
  93. // 表达式
  94. exp := "33+2*6/1-2" // 字符串本身也是切片
  95. // 定义需要的变量
  96. num1 := 0
  97. num2 := 0
  98. oper := 0
  99. keepNum := "" // 字符串 用于拼接多位数
  100. // 定义索引,扫描表达式
  101. index := 0
  102. for {
  103. ch := exp[index : index+1] // 每次拿到一个字符, 如果数字大于1位就会出问题, 在非符号字符入栈时处理
  104. temp := int([]byte(ch)[0]) // 字符对应的 ASCII 码
  105. if operStack.IsOper(temp) {
  106. // 符号
  107. if operStack.Top == -1 {
  108. // 1. 符号栈为空
  109. operStack.Push(temp)
  110. } else {
  111. // 2. 符号栈不为空
  112. // 2.1 栈中的符号优先级大于等于即将入栈的符号
  113. if operStack.Priority(operStack.arr[operStack.Top]) >= operStack.Priority(temp) {
  114. num1, _ = numStack.Pop()
  115. num2, _ = numStack.Pop()
  116. oper, _ = operStack.Pop()
  117. result := operStack.Cal(num1, num2, oper)
  118. numStack.Push(result)
  119. operStack.Push(temp)
  120. } else {
  121. // 2.2 栈中的符号优先级小于即将入栈的符号
  122. operStack.Push(temp)
  123. }
  124. }
  125. } else {
  126. // 数字
  127. // 多位数拼接
  128. keepNum += ch
  129. // 判断扫描的下一位是不是运算符, 边界问题(表达式最后, 预防溢出)
  130. if index == len(exp)-1 {
  131. // 字符 转数字
  132. val, _ := strconv.Atoi(keepNum) // Atoi是ParseInt(s, 10, 0)的简写。 返回的就是 int 类型
  133. numStack.Push(val)
  134. } else {
  135. // 向后看一位
  136. if operStack.IsOper(int([]byte(exp[index+1 : index+2])[0])) {
  137. val, _ := strconv.Atoi(keepNum) // Atoi是ParseInt(s, 10, 0)的简写。 返回的就是 int 类型
  138. numStack.Push(val)
  139. keepNum = ""
  140. }
  141. // 其它情况不做处理,index++, 判断下一个字符
  142. }
  143. /*
  144. // 字符 转数字
  145. // val, _ := strconv.ParseInt(ch, 10, 0) // 返回 int64, 需要转 int(val)
  146. val, _ := strconv.Atoi(ch) // Atoi是ParseInt(s, 10, 0)的简写。 返回的就是 int 类型
  147. numStack.Push(val)
  148. */
  149. }
  150. // 判断扫描位置
  151. if index+1 == len(exp) {
  152. fmt.Println("扫描到最后了")
  153. break
  154. }
  155. index++
  156. }
  157. // 扫描完毕,之后对数栈和符号栈剩余元素处理
  158. for {
  159. if operStack.Top == -1 {
  160. fmt.Println("没有运算符了, 数栈中的值就是计算结果")
  161. break
  162. }
  163. num1, _ = numStack.Pop()
  164. num2, _ = numStack.Pop()
  165. oper, _ = operStack.Pop()
  166. result := operStack.Cal(num1, num2, oper)
  167. numStack.Push(result)
  168. }
  169. // 如果计算正确,数栈中只剩下一个元素,就是计算结果
  170. res, _ := numStack.Pop()
  171. fmt.Printf("表达式: %s = %v \n", exp, res)
  172. }