逆波兰表达式(中缀转后缀表达式)
##一 问题描述
解析并计算 9+(3-1)*3+10/2 为后缀表达式 [9,3,1,-,3,*,+,10,2,/,+ ]
中缀转后缀
###1 描述:
在我们转换中缀到后缀的过程,其实是一个取出表达式中的操作数或运算符号进行重排列的过程。
主要的转换都是根据运算符号来进行的,从表达式中取出来的数字都会放入栈中,然后根据取出来运算符号来解析出新表达式。
但是运算符号其实也有一个优先级,低优先级的符号应该比高优先级符号的解析优先级别要低,也就是先解析高优先级符号,然后才会解析低优先级符号。
比如 9+2*3,此时应该先解析*也就是 2,3,* 然后才会解析 + 。最终结果为: 9 2 3 * +
因此在解析符号的时候会做一个判断,根据优先级来判断是否立即解析还是继续将符号入栈。
关于操作符优先级:
1)其中(最高,)最低。按顺序为: ( > * , / > + ,- > ) > #
2)运算符在栈内优先级(isp)和栈外优先级(icp)的计算优先级是相反的
。
3)最后为了简化栈判断,我们加了一个标志位,假设该栈中有一个最低优先级的特殊符号“#”。
各运算符及符号优先级:参见
[http://baike.baidu.com/view/552648.htm](http://baike.baidu.com/view/552648.htm)
##2 算法分析
从左到右遍历,如果是操作数则输出。
如果是运算符号,判断与栈顶符号的优先级,高于栈顶符号直接进栈。
否则,栈顶符号出栈。继续出栈知道栈顶运算符的优先级低于当前运算符。
然后将当前预算符入栈。
若当前运算符为'(',直接入栈;
若为')',出栈并顺序输出运算符直到遇到第一个'(',遇到的第一个'('出栈但不输出;
若为四则运算符,比较栈顶元素与当前元素的优先级:
如果 栈顶元素运算符优先级 >= 当前元素的优先级,出栈并顺序输出运算符直到 栈顶元素优先级 < 当前元素优先级,然后当前元素入栈;
如果 栈顶元素 < 当前元素,直接入栈。
###3 go语言实现
package main
import (
"fmt"
)
/*
* 定义节点
*/
type Node struct {
Data string
Next *Node
}
/*
* 定义栈
*/
type Stack struct {
Top *Node
Length int
}
func NewStack() *Stack {
return &Stack{Top: nil, Length: 0}
}
/*
* 压栈
*/
func (list *Stack) Push(data string) error {
node := &Node{Data: data, Next: list.Top}
list.Top = node
list.Length++
return nil
}
/*
* 出栈
*/
func (list *Stack) Pop() (string, error) {
if list.Length == 0 {
return "", fmt.Errorf("the list is empty")
}
node := list.Top
list.Top = node.Next
list.Length--
return node.Data, nil
}
/**************************************************/
//栈外优先级icp(In coming priority)
func GetIcp(oper string) int {
switch oper {
case ")":
return 1
case "(":
return 8
case "+":
fallthrough
case "-":
return 2
case "*":
fallthrough
case "/":
fallthrough
case "%":
return 4
case "#":
return 0
}
return 0
}
//栈内优先级isp(In stack priority)
func GetIsp(oper string) int {
switch oper {
case ")":
return 8
case "(":
return 1
case "+":
fallthrough
case "-":
return 3
case "*":
fallthrough
case "/":
fallthrough
case "%":
return 5
case "#":
return 0
}
return 0
}
func IsOperator(oper string) bool {
switch oper {
case "(":
fallthrough
case ")":
fallthrough
case "+":
fallthrough
case "-":
fallthrough
case "*":
fallthrough
case "/":
return true
default:
return false
}
return false
}
func CenterToEnd(expr []string) []string {
stack := &Stack{Top: &Node{Data: "#", Next: nil}, Length: 0}
retexpr := make([]string, 0)
for _, v := range expr {
if !IsOperator(v) {
retexpr = append(retexpr, v)
} else {
if stack.Length == 0 {
stack.Push(v)
} else {
//遇到")",则出栈并输出。直到"(","("出栈不输出。
if GetIcp(v) == 1 {
for GetIcp(stack.Top.Data) != 8 {
data, _ := stack.Pop()
retexpr = append(retexpr, data)
}
stack.Pop()
} else if GetIcp(v) >= GetIsp(stack.Top.Data) {
//比较运算符>的情况
stack.Push(v)
} else {
//比较运算符<=的情况
for GetIcp(v) < GetIsp(stack.Top.Data) {
data, _ := stack.Pop()
retexpr = append(retexpr, data)
}
stack.Push(v)
}
}
}
}
//输出栈中剩余计算符
for stack.Length > 0 {
data, _ := stack.Pop()
retexpr = append(retexpr, data)
}
return retexpr
}
func main() {
expr := []string{"9", "+", "(", "3", "-", "1", ")", "*", "3", "+", "10", "/", "2"}
retexpr := CenterToEnd(expr)
for _, v := range retexpr {
fmt.Println("value=========", v)
}
}