Go(Golang)中将Infix转换为Postfix表达式的方法

298 阅读3分钟

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行的注释来检查每次推送和弹出操作后的栈的状态。