惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
WordPress大学
WordPress大学
罗磊的独立博客
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Help Net Security
S
SegmentFault 最新的问题
C
Check Point Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
Engineering at Meta
Engineering at Meta
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
D
DataBreaches.Net
雷峰网
雷峰网
GbyAI
GbyAI
宝玉的分享
宝玉的分享

Mohuishou

如何实现支持多集群的 Kubernetes Operator? 第三方应用如何调用我们 kubebuilder 生成的自定义资源? Kubernetes 简明教程 k8s job 为何迟迟不能结束? Go 工程化(十一) 如何优雅的写出 repo 层代码 Go 工程化(十) 如何在整洁架构中使用事务? 给博客添加章节目录 使用 Notion Database 管理静态博客文章 一个普通 Go 开发的三年 4. localhost 就一定是 localhost 么? Go可用性(七) 总结: 一张图串联可用性知识点 Go可用性(六) 熔断 10. 总结 9. kubebuilder 进阶: 源码分析 8. kubebuilder 进阶: webhook 7. kubebuilder 进阶: 测试 6. kubebuilder 实战: status & event 5. kubebuilder 实战: CRUD 4. kustomize 简明教程 3. KubeBuilder 简明教程 2. Kind: 如何快速搭建本地 K8s 开发环境? 1. Operator概述: 如何对 Kubernetes 进行扩展 Go可用性(五) 自适应限流 Go可用性(四) 漏桶算法 Go可用性(三) 令牌桶的实现 rate/limt Go可用性(二) 令牌桶原理及使用 Go可用性(一) 隔离设计 Go并发编程(十二) Singleflight Go工程化(九) 项目重构实践 Go工程化(八) 单元测试
4. 栈上: 如何实现一个计算器
Mohuishou · 2020-11-23 · via Mohuishou

栈是一种“操作受限”的线性表,后进者先出,先进者后出。
比较典型的例子就是我们在叠盘子的时候,叠的时候从下到上一个一个磊起来,取的时候,再从上到下一个一个的拿出来。
说到先入后出这种特性,在 Go 中你第一时间想到了什么?不知道是否和我的答案一样, defer 
01_stack.drawio.svg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package calculation

import (
"fmt"
"strconv"
)

// 操作符的优先级
var operatorPriority = map[string]int{
"+": 0,
"-": 0,
"*": 1,
"/": 1,
"(": 2,
")": 2,
}

// Calculator 计算器
type Calculator struct {
nums *StackInt
operators *Stack
exp string
}

// NewCalculator NewCalculator
func NewCalculator(exp string) *Calculator {
return &Calculator{
nums: NewStackInt(),
operators: NewStack(),
exp: exp,
}
}

// Calculate 获取计算结果
func (c *Calculator) Calculate() int {
l := len(c.exp)
for i := 0; i < l; i++ {
switch e := (c.exp[i]); e {
case ' ':
continue
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
// 一直往后获取数字,如果下一个还是数字说明这一个数还不完整
j := i
for j < l && c.exp[j] <= '9' && c.exp[j] >= '0' {
j++
}
n, _ := strconv.Atoi(c.exp[i:j])
i = j - 1
c.nums.Push(n)
case '+', '-', '*', '/':
// 从计算符栈中获取栈顶元素,如果当前操作符的优先级低于栈顶元素的优先级
// 并且栈顶元素不为空,和括号
// 那么从数据栈中取两个数据和栈顶操作符进行计算
pre := c.operators.Pop()
for pre != "" && pre != "(" && operatorPriority[string(e)] <= operatorPriority[pre] {
c.nums.Push(c.calc(pre))
pre = c.operators.Pop()
}
if pre != "" {
c.operators.Push(pre)
}
c.operators.Push(string(e))
case '(':
c.operators.Push(string(e))
case ')':
// 碰到右括号之后就一直不断操作符栈中弹出元素,并且取两个数据进行计算
// 直到碰到左括号为止
for o := c.operators.Pop(); o != "(" && o != ""; o = c.operators.Pop() {
c.nums.Push(c.calc(o))
}
default:
panic("invalid exp")
}
}
// 最后如果不存在操作符,说明数据栈中的栈顶元素就是最后结果
o := c.operators.Pop()
if o == "" {
return c.nums.Pop()
}
// 如果存在,就把最后的数据进行计算后返回
return c.calc(o)
}

// calc 单次计算操作,o: 计算符
func (c *Calculator) calc(o string) int {
b := c.nums.Pop()
a := c.nums.Pop()

fmt.Printf("%d %s %d\n", a, o, b)

switch o {
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
return a / b
}

return 0
}

// calculate 计算器,支持加减乘除
func calculate(s string) int {
return NewCalculator(s).Calculate()
}