最近听说逆波兰计算法,看了一下就是需要将我们常见的中缀表达式转换为后缀表达式。前两天不是刚写了一个栈吗,想到刚好可以把这个栈实际运用一下,于是写了一个中缀转后缀的函数。
栈的代码:
package stack
import (
"fmt"
)
type Stacker struct{
i int
data []interface{}
}
func (s *Stacker) Push( v interface{}) {
if len(s.data) == 100{//容量为100的栈,后进先出
return
}
s.data = append(s.data, v)
s.i++
fmt.Printf("stacker:%v\n",s)
}
func (s *Stacker) Pop () interface{}{
s.i--
r := s.data[s.i]
s.data = append(s.data[:s.i])
fmt.Printf("popvalue:%v\n",r)
fmt.Printf("stacker:%v\n",s)
return r
}
转后缀表达式代码:
package stack
import (
"fmt"
"github.com/aws/aws-sdk-go/private/util"
)
//波兰算法
//中缀表达式转化为后缀表达式
func ToSuffix(pre string) *Stacker {
suffixStacker := new(Stacker) //后缀表达式
opStacker := new(Stacker) //符号栈
pre =util.Trim(pre)
//3*4 + 5 *(4+3)-15 -> 34*543+*15- " 5+4*3+2 -> 543*+2+ 5+4*3+(1+2)*5 -> 543*+12+5*+
str := ""
preArr := []rune(pre)
fmt.Printf("%v",preArr)
//for I, _ := range preArr {
for I := 0; I<len(preArr);I++{
println(I)
item := preArr[I] //48-57 0-9
sItem := string(item)
if item >= 48 && item <= 57 { //数字
str = str + sItem //组成数字字符串
} else {
if sItem != "+" && sItem != "-" && sItem != "*" && sItem != "\\" && sItem != "(" && sItem != ")" {
return nil
}
if str != ""{
suffixStacker.Push(str)
str = ""//清空字符串
}
//遇到符号,则数字结束,数字入栈
op1 := sItem
if op1 != ")" {
if opStacker.i==0{
opStacker.Push(op1)
continue
}
if op1 == "("{
opStacker.Push(op1)
continue
}
//检查优先级
topOp := opStacker.data[opStacker.i-1] //符号栈栈顶元素
if topOp == "(" { //当栈顶元素不是运算符时符号直接入栈
opStacker.Push(op1)
continue
}
if op1 == "*" || op1 == "\\" { //乘除的优先级高于加减 op1 > topOp
opStacker.Push(op1)
continue
}
//当前运算符优先级小于符号栈栈顶优先级 op1<topOp
for {
if opStacker.i == 0 {
break
}
topOp = opStacker.data[opStacker.i-1] //符号栈栈顶元素
opStacker.Pop()
suffixStacker.Push(topOp)
continue
}
opStacker.Push(op1)
} else {
//遇到) 依次出栈到(
for {
if opStacker.i <=0 {
break //正常不会出现此,仅为了防止死循环
}
t := opStacker.Pop()
if t == "(" {
break
} else {
suffixStacker.Push(t)
}
}
}
}
}
suffixStacker.Push(str)
for {
if opStacker.i <= 0 {
break
}
t := opStacker.Pop()
suffixStacker.Push(t)
}
return suffixStacker
}
算换算法三个原则:1、凡是遇到操作符,则认为数字输入已结束,将数字输入到目标栈
2、当遇到运算符“)”则符号栈依次出栈,直到遇到“(”
3、当其他运算符 op1,与栈顶运算符(topOp)比较优先级。当op1>topOp时,op1直接入栈;
当op1<=topOp时,栈顶元素出栈,压入到目标栈,直到栈顶元素op1>topOp,停止出栈。将op1入栈到符号栈;
测试代码:
func TestSuffixExpress(t *testing.T){
//3*4 + 5 *(4+3)-15 -> 34*543+*15- " 5+4*3+2 -> 543*+2+ 5+4*3+(1+2)*5 -> 543*+12+5*+
//pre := "3*4+5*(4+3)-15"
//pre := "5+4*3+2"
pre := "5+4*3+(1+2)*5+23*5-2+1"
rs := stack2.ToSuffix(pre)
fmt.Printf("%v->%v\n",pre,rs)
测试结果:
当取得后缀表达式后,要做计算器就简单了。