概念
- 前綴表達式又稱波蘭式,前綴表達式的運算符位於操作數之前。比如:
- × + 3 4 5 6
- 中綴表達式就是常見的運算表達式,如
(3+4)×5-6
- 後綴表達式又稱逆波蘭表達式,與前綴表達式相似,只是運算符位於操作數之後,比如:3 4 + 5 × 6 -
人類最熟悉的一種表達式1+2,(1+2)3,3+42+4等都是中綴表示法。對於人們來說,也是最直觀的一種求值方式,先算括號裏的,然後算乘除,最後算加減,但是,計算機處理中綴表達式卻並不方便。
我們先看一個例子 (3+4)× 5 - 6
後綴表達式3 4 + 5 × 6 -
的計算
- 從左至右掃描,將3和4壓入堆棧;
- 遇到+運算符,因此彈出4和3(4爲棧頂元素,3爲次頂元素,注意與前綴表達式做比較),計算出3+4的值,得7,再將7入棧;
- 將5入棧;
- 接下來是×運算符,因此彈出5和7,計算出7×5=35,將35入棧;
- 將6入棧;
- 最後是-運算符,計算出35-6的值,即29,由此得出最終結果。
中綴表達式轉換爲後綴表達式
1.數字直接入隊列
2.運算符要與棧頂元素比較
①棧爲空直接入棧
②運算符優先級大於棧頂元素優先級則直接入棧
③小於或等於則出棧入列,再與棧頂元素進行比較,直到運算符優先級小於棧頂元
素優先級後,操作符再入棧
3.操作符是 (
則無條件入棧
4.操作符爲 )
,則依次出棧入列,直到匹配到第一個“(”
爲止,此操作符直接捨棄,“(”
直接出棧捨棄
public class SuffixAlgorithm {
private static char LEFT_BRACKET = Operator.LEFT_BRACKET.value;
private static char RIGHT_BRACKET = Operator.RIGHT_BRACKET.value;
private static void rpn(Stack<Character> operators, Stack output, String exp){
char[] chars = exp.toCharArray();
int len = chars.length;
int bracket = 0; // operators中的左括號的數量
for (int i = 0; i < len; ) {
int pre = i;//處理開始下標
boolean digital = Boolean.FALSE; //是否爲數字(只要不是運算符,都是數字),用於截取字符串
while (i < len && !Operator.isOperator(chars[i])) {
i++;
digital = Boolean.TRUE;
}
if (digital) {//如果是數字,直接壓入output
output.push(exp.substring(pre, i));
}else{
char o = chars[i++];
if (o == LEFT_BRACKET){//左括號直接壓入output
operators.push(o);
bracket++;
continue;
}
if(o == RIGHT_BRACKET){//是右括號
if(bracket < 1){
throw new IllegalArgumentException("can't find '('");
}
//將operators棧頂彈出壓入output直到左括號
while (!operators.empty()) {
char top = operators.pop();
if (top == LEFT_BRACKET) {
break;
}
output.push(top);
}
bracket--;
continue;
}
char p;
while (!operators.empty()
&& ( p = operators.peek()) != LEFT_BRACKET
&& Operator.cmp(o, p) <= 0){
output.push(operators.pop());
}
operators.push(o);
}
}
while (!operators.empty()){
output.push(operators.pop());
}
}
public static void main(String[] args) {
System.out.println(rpn("a*(b-c*d)+e-f/g*(h+i*j-k)"));
System.out.println("a,b,c,d,*,-,*,e,+,f,g,/,h,i,j,*,+,k,-,*,-");
}
public static String rpn(String exp){
Stack<Character> operators = new Stack<>();
Stack<Character> output = new Stack();
rpn(operators, output, exp);
String str = "";
for(int i=0; i<output.size();i++){
str += String.valueOf(output.get(i));
}
return str;
}
static enum Operator {
ADD('+', 1), SUBTRACT('-', 1),
MULTIPLY('*', 2), DIVIDE('/', 2),
LEFT_BRACKET('(', 3), RIGHT_BRACKET(')', 3);
char value;
int priority;
Operator(char value, int priority) {
this.value = value;
this.priority = priority;
}
/**
* 比較兩個符號的優先級
*
* @param c1
* @param c2
* @return c1的優先級是否比c2的高,高則返回正數,等於返回0,小於返回負數
*/
public static int cmp(char c1, char c2) {
int p1 = 0;
int p2 = 0;
for (Operator o : Operator.values()) {
if (o.value == c1) {
p1 = o.priority;
}
if (o.value == c2) {
p2 = o.priority;
}
}
return p1 - p2;
}
/**
* 枚舉出來的才視爲運算符,用於擴展
*
* @param c
* @return
*/
public static boolean isOperator(char c) {
for (Operator o : Operator.values()) {
if (o.value == c) {
return true;
}
}
return false;
}
public static Operator findOperator(char c){
for (Operator o : Operator.values()) {
if (o.value == c) {
return o;
}
}
return null;
}
}
}