您的位置:首页 > 编程语言 > Go语言

栈_逆波兰表达式_计算器实现_Golang版本

2015-02-01 09:25 281 查看
借助栈与逆波兰表达式 实现一个计算器,编程语言用的是Golang。

逆波兰表达式可以讲复杂的计算过程转化为简单的操作过程,进而得出答案。 比如 (a+b)*(b-c) 按照逆波兰表达式的规则得到 :ab+bc-*  

然后将该表达式的字符以及符号,按照从左到右的顺序,依次入栈,一碰到符号则将栈顶前两个元素取出,做运算然后放入栈内,重复该操作,直到表达式结束。

下面将结合栈与逆波兰表达式写一个简易计算器。

运行命令如下

go run counter.go --expression=\(3-5\)*4-\(5*8\)/3+78*9

代码示例:

package main

import (
"fmt"
"strconv"
"flag"
)

type StackNode struct {
Data interface{}
next *StackNode
}

type LinkStack struct {
top *StackNode
Count int
}

func (this *LinkStack) Init() {
this.top = nil
this.Count = 0
}

func (this *LinkStack) Push(data interface{}) {
var node *StackNode = new(StackNode)
node.Data = data
node.next = this.top
this.top = node
this.Count++
}

func (this *LinkStack) Pop() interface{} {
if this.top == nil {
return nil
}
returnData := this.top.Data
this.top = this.top.next
this.Count--
return returnData
}

//Look up the top element in the stack, but not pop.
func (this *LinkStack) LookTop() interface{} {
if this.top == nil {
return nil
}
return this.top.Data
}

var str *string = flag.String("expression", "", "")

func main() {
flag.Parse()
fmt.Println(*str)
fmt.Println(Count(*str))
}

func Count(data string) float64 {
//TODO 检查字符串输入
var arr []string = generateRPN(data)
return calculateRPN(arr)
}

func calculateRPN(datas []string) float64 {
var stack LinkStack
stack.Init()
for i := 0; i < len(datas); i++ {
if isNumberString(datas[i]) {
if f, err := strconv.ParseFloat(datas[i], 64); err != nil {
panic("operatin process go wrong.")
} else {
stack.Push(f)
}
} else {
p1 := stack.Pop().(float64)
p2 := stack.Pop().(float64)
p3 := normalCalculate(p2, p1, datas[i])
stack.Push(p3)
}
}
res := stack.Pop().(float64)
return res
}

func normalCalculate(a,b float64, operation string) float64 {
switch operation{
case "*":
return a * b
case "-":
return a - b
case "+":
return a + b
case "/":
return a / b
default:
panic("invalid operator")
}
}

func generateRPN(exp string) []string {

var stack LinkStack
stack.Init()

var spiltedStr []string = convertToStrings(exp)
var datas []string

for i := 0; i < len(spiltedStr); i++ { // 遍历每一个字符
tmp := spiltedStr[i] //当前字符

if !isNumberString(tmp) { //是否是数字
// 四种情况入栈
// 1 左括号直接入栈
// 2 栈内为空直接入栈
// 3 栈顶为左括号,直接入栈
// 4 当前元素不为右括号时,在比较栈顶元素与当前元素,如果当前元素大,直接入栈。
if tmp == "(" ||
stack.LookTop() == nil || stack.LookTop().(string) == "(" ||
( compareOperator(tmp, stack.LookTop().(string)) == 1 && tmp != ")" ) {
stack.Push(tmp)
} else { // ) priority
if tmp == ")" { //当前元素为右括号时,提取操作符,直到碰见左括号
for {
if pop := stack.Pop().(string); pop == "(" {
break
} else {
datas = append(datas, pop)
}
}
} else { //当前元素为操作符时,不断地与栈顶元素比较直到遇到比自己小的(或者栈空了),然后入栈。
for {
pop := stack.LookTop()
if pop != nil && compareOperator(tmp, pop.(string)) != 1 {
datas = append(datas, stack.Pop().(string))
} else {
stack.Push(tmp)
break
}
}
}
}

} else {
datas = append(datas, tmp)
}
}

//将栈内剩余的操作符全部弹出。
for {
if pop := stack.Pop(); pop != nil {
datas = append(datas, pop.(string))
} else {
break
}
}
return datas
}

// if return 1, o1 > o2.
// if return 0, o1 = 02
// if return -1, o1 < o2
func compareOperator(o1, o2 string) int {
// + - * /
var o1Priority int
if o1 == "+" || o1 == "-" {
o1Priority = 1
} else {
o1Priority = 2
}
var o2Priority int
if o2 == "+" || o2 == "-" {
o2Priority = 1
} else {
o2Priority = 2
}
if o1Priority > o2Priority {
return 1
} else if o1Priority == o2Priority {
return 0
} else {
return -1
}
}

func isNumberString(o1 string) bool {
if o1 == "+" || o1 == "-" || o1 == "*" || o1 == "/" || o1 == "(" || o1 == ")" {
return false
} else {
return true
}
}

func convertToStrings(s string) []string {
var strs []string
bys := []byte(s)
var tmp string
for i := 0; i < len(bys); i++ {
if !isNumber(bys[i]) {
if tmp != "" {
strs = append(strs, tmp)
tmp = ""
}
strs = append(strs, string(bys[i]))
} else {
tmp = tmp+string(bys[i])
}
}
strs = append(strs, tmp)
return strs
}

func isNumber(o1 byte) bool {
if o1 == '+' || o1 == '-' || o1 == '*' || o1 == '/' || o1 == '(' || o1 == ')' {
return false
} else {
return true
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: