Infix到Postfix的转换
在本教程中,我们将看到什么是Infix和Postfix表达式,Postfix表达式比Infix的优点,以及我们如何将Infix表达式转换为Postfix表达式。我们将在另一个教程中介绍Postfix表达式的评估。
Infix Expression: In infix expression, the operator is in between pair of operands like (a op b).
example: a+b, 2/2 .
Postfix Expression: In postfix expression, the operator is placed post to both operands like (a b op).
example: ab+, 22/ .
这些是后缀表达式相对于Infix的一些优势。
-
后缀表达式的评估比Infix表达式的评估更容易。
-
后缀表达式中不需要括号。
-
后缀表达式的求值需要单次扫描。
-
评估速度比Infix记数法快。
算法
-
从左到右扫描Infix表达式。
-
如果当前扫描的字符是一个操作数,则输出它。
-
否则,如果当前扫描的运算符的优先级大于堆栈中的运算符的优先级(或者堆栈是空的或者堆栈中含有'('),则推送它。 否则,从堆栈中弹出所有优先级大于或等于被扫描运算符的运算符。做完这些后,将扫描到的运算符推到堆栈中。(如果你在弹出时遇到小括号,那么在那里停止,并将扫描的运算符推入堆栈)。
-
如果扫描到的字符是一个'(',就把它推到堆栈里。
-
如果扫描到的字符是')',弹出堆栈并输出,直到遇到'(',并丢弃两个括号。
-
重复步骤2-6,直到扫描完infix表达式。
-
打印输出
-
从堆栈中弹出并输出,直到它不是空的。
下面是上述算法的例子。
英缀表达式是a+b,后缀表达式是ab+ 。
-
a是操作数(输出它)//output=a
-
+是运算符(推入堆栈)。
-
b是操作数(输出)//输出=ab
-
英缀表达式被完全扫描,现在从堆栈中取出并加入输出,因此后缀表达式成为ab+。
类似的是
英缀表达式是
a+b*c+d
那么后缀表达式是
abc*+d+:
- a是操作数(输出它)//output=a
- +是运算符(将其推入堆栈)//堆栈=+
- b是操作数(输出它)//ab
- *是运算符,优先级比+高,(将其推入堆栈)//stack=+*
- c是操作数(输出它)//输出=abc
- +是运算符,但比堆栈中的运算符低,从堆栈中弹出并推入+ //output=abc*+, stack=+
- d是操作数(输出它)//output=abc*+d
- 从堆栈中弹出并添加到输出中 //output=abc*+d+
实施。
下面是在golang中实现的Infix到Postfix的转换。
package main
import "fmt"
type Stack []string
//IsEmpty: check if stack is empty
func (st *Stack) IsEmpty() bool {
return len(*st) == 0
}
//Push a new value onto the stack
func (st *Stack) Push(str string) {
*st = append(*st, str) //Simply append the new value to the end of the stack
}
//Remove top element of stack. Return false if stack is empty.
func (st *Stack) Pop() bool {
if st.IsEmpty() {
return false
} else {
index := len(*st) - 1 // Get the index of top most element.
*st = (*st)[:index] // Remove it from the stack by slicing it off.
return true
}
}
//Return top element of stack. Return false if stack is empty.
func (st *Stack) Top() string {
if st.IsEmpty() {
return ""
} else {
index := len(*st) - 1 // Get the index of top most element.
element := (*st)[index] // Index onto the slice and obtain the element.
return element
}
}
//Function to return precedence of operators
func prec(s string) int {
if s == "^" {
return 3
} else if (s == "/") || (s == "*") {
return 2
} else if (s == "+") || (s == "-") {
return 1
} else {
return -1
}
}
func infixToPostfix(infix string) string {
var sta Stack
var postfix string
for _, char := range infix {
opchar := string(char)
// if scanned character is operand, add it to output string
if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') {
postfix = postfix + opchar
} else if char == '(' {
sta.Push(opchar)
} else if char == ')' {
for sta.Top() != "(" {
postfix = postfix + sta.Top()
sta.Pop()
}
sta.Pop()
} else {
for !sta.IsEmpty() && prec(opchar) <= prec(sta.Top()) {
postfix = postfix + sta.Top()
sta.Pop()
}
sta.Push(opchar)
}
}
// Pop all the remaining elements from the stack
for !sta.IsEmpty() {
postfix = postfix + sta.Top()
sta.Pop()
}
return postfix
}
func main() {
//infix := "a+b"
//infix := "a+b*c+d"
//infix := "a+b*(c^d-e)^(f+g*h)-i" // abcd^e-fgh*+^*+i-
//infix := "1+2+3*4+5/5-2"
infix := "2+3*(2^3-5)^(2+1*2)-4" //abcd^e-fgh*+^*+i-
postfix := infixToPostfix(infix)
fmt.Printf("%s infix has %s postfix ", infix, postfix)
}
输出。
2+3*(2^3-5)^(2+1*2)-4 infix has 2323^5-212*+^*+4- postfix
我们可以通过在Push和Pop函数声明中取消对fmt.Println行的注释来检查每次推送和弹出操作后的栈的状态。