版權(quán)聲明:本文源自簡(jiǎn)書(shū)tianma,轉(zhuǎn)載請(qǐng)務(wù)必注明出處: http://www.lxweimin.com/p/a0d4764eba18
中綴表達(dá)式: 是一個(gè)通用的算術(shù)或邏輯公式表示方法, 操作符是以中綴形式處于的中間(例:3 + 4),中綴表達(dá)式是人們常用的算術(shù)表示方法,但是不易被計(jì)算機(jī)所解析。
后綴表達(dá)式:是一個(gè)通用的算術(shù)或邏輯公式表示方法, 操作符是后綴形式處于操作數(shù)的后面(例:3 4 +),后綴表達(dá)式雖然不是人們所習(xí)慣的運(yùn)算表示方法,但是易被計(jì)算機(jī)解析。
例如:對(duì)于中綴表達(dá)式 9+(3-1)*2+10/2 , 其后綴表達(dá)式是 9 3 1 - 3 * + 10 2 / + , 那么為了方便計(jì)算機(jī)解析計(jì)算,我們需要將中綴表達(dá)式轉(zhuǎn)換成后綴表達(dá)式,然后再對(duì)后綴表達(dá)式進(jìn)行解析。
1. 中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式:
- 當(dāng)讀到一個(gè)操作數(shù)時(shí),立即將它放到輸出中。讀到的是操作符則需要接著判斷是否該入棧。讀到的是左圓括號(hào)則入棧。
- 在讀到操作符時(shí),如果棧為空或者棧頂操作符為(,則入棧。如果棧頂操作符不為(,且此操作符優(yōu)先級(jí)小于或等于此時(shí)棧頂操作符,則將棧中元素彈出直至 ①遇到左括號(hào) 或者 ②棧頂元素為更低優(yōu)先級(jí) 或者 ③棧為空為止,并將當(dāng)前操作符入棧;否則當(dāng)前操作符繼續(xù)入棧。操作符中,+-優(yōu)先級(jí)低,*/優(yōu)先級(jí)高。
- 如果遇到一個(gè)右括號(hào),那么就將棧中元素彈出并輸出直至遇到左括號(hào)為止。但是這個(gè)左括號(hào)只被彈出,并不輸出。
- 如果讀到輸入的末尾,若棧不為空則將棧元素彈出直到該棧變成空棧,并將彈出的符號(hào)寫(xiě)到輸出中。
"9+(3-1)2+10/2" 轉(zhuǎn)換過(guò)程:*
操作過(guò)程 | 棧中元素 | 輸出 |
---|---|---|
讀入 9,輸出 | 9 | |
讀入 +,棧為空,規(guī)則2,入棧 | + | 9 |
讀入 ( ,左括號(hào),規(guī)則1,入棧 | + ( | 9 |
讀入 3,輸出 | + ( | 9 3 |
讀入 -,棧頂為(,規(guī)則2,入棧 | + ( - | 9 3 |
讀入 1,輸出 | + ( - | 9 3 1 |
讀入 ) ,右括號(hào),規(guī)則3,出棧并輸出 | + | 9 3 1 - |
讀入 *,*優(yōu)先級(jí)高于棧頂+,規(guī)則,2,入棧 | + * | 9 3 1 - |
讀入 3,輸出 | + * | 9 3 1 - 3 |
讀入 +,+優(yōu)先級(jí)低于棧頂*,規(guī)則2,棧中元素出棧,當(dāng)前操作符入棧 | + | 9 3 1 - 3 * + |
讀入 10, 輸出 | + | 9 3 1 - 3 * + 10 |
讀入 / , /優(yōu)先級(jí)高于+,入棧 | + / | 9 3 1 - 3 * + 10 |
讀入 2, 輸出 | + / | 9 3 1 - 3 * + 10 |
讀至末尾,規(guī)則4,棧不為空,棧中元素出棧并輸出 | 9 3 1 - 3 * + 10 / + |
2. 后綴表達(dá)式計(jì)算最終結(jié)果:
- 從左到右遍歷表達(dá)式的每個(gè)數(shù)字和符號(hào),遇到是數(shù)字則進(jìn)棧,遇到是運(yùn)算符則將棧頂兩個(gè)元素出棧,進(jìn)行運(yùn)算并將運(yùn)算結(jié)果進(jìn)棧;
- 遍歷完后綴表達(dá)式,此時(shí)棧中剩余的數(shù)字就是運(yùn)算結(jié)果。
"9 3 1 - 3 * + 10 2 / +" 計(jì)算過(guò)程:
操作過(guò)程 | 棧中元素 |
---|---|
讀入 9,入棧 | 9 |
讀入 3,入棧 | 9 3 |
讀入 1,入棧 | 9 3 1 |
讀入 -,運(yùn)算并將結(jié)果入棧 | 9 2 |
讀入 3,入棧 | 9 2 3 |
讀入 *,運(yùn)算并將結(jié)果入棧 | 9 6 |
讀入 +,運(yùn)算并將結(jié)果入棧 | 15 |
讀入 10,入棧 | 15 10 |
讀入 2,入棧 | 15 10 2 |
讀入 /,運(yùn)算并將結(jié)果入棧 | 15 5 |
讀入 +,運(yùn)算并將結(jié)果入棧 | 20 |
讀入完畢,棧中元素即為結(jié)果 | 20 |
簡(jiǎn)單中綴表達(dá)式計(jì)算的java實(shí)現(xiàn):
public class SimpleCalcutor {
private class Item {
private String value;
private Integer number;
public Item(String value) {
this.value = value;
try {
number = Integer.parseInt(value);
} catch (Exception ignore) {
}
}
public boolean isNumber() {
return number != null;
}
public int getNumber() {
if (isNumber())
return number;
throw new NumberFormatException();
}
public boolean isAdd() {
return "+".equals(value);
}
public boolean isSub() {
return "-".equals(value);
}
public boolean isMul() {
return "*".equals(value);
}
public boolean isDiv() {
return "/".equals(value);
}
public boolean isLeftBracket() {
return "(".equals(value);
}
public boolean isRightBracket() {
return ")".equals(value);
}
public int getPriority() {
if (isAdd() || isSub())
return 0;
if (isMul() || isDiv())
return 1;
throw new RuntimeException("This is not +, -, *, /");
}
@Override
public String toString() {
return value != null ? value.toString() : null;
}
}
/**
* 計(jì)算結(jié)果
*
* @param calStr
* @return
*/
public int calculate(String calStr) {
List<Item> infixes = parse(calStr);
List<Item> postfixes = infix2postfix(infixes);
return calculateByPostfix(postfixes);
}
/**
* 利用正則表達(dá)式將待計(jì)算的字符串轉(zhuǎn)化為L(zhǎng)ist<Item>形式 ,如 10/2 -> [10, /, 2]
*
* @param calStr
* @return
*/
private List<Item> parse(String calStr) {
Pattern pattern = Pattern.compile("\\D|\\d+");
Matcher m = pattern.matcher(calStr);
List<Item> items = new ArrayList<Item>();
while (m.find()) {
items.add(new Item(m.group(0)));
}
return items;
}
/**
* 中綴表達(dá)式轉(zhuǎn)換為后綴表達(dá)式
* <p>
* 1.當(dāng)讀到一個(gè)操作數(shù)時(shí),立即將它放到輸出中。讀到的是操作符則需要接著判斷是否該入棧。讀到的是左圓括號(hào)則入棧。<br>
* 2.如果遇到一個(gè)右括號(hào),那么就將棧中元素彈出并輸出直至遇到左括號(hào)為止。但是這個(gè)左括號(hào)只被彈出,并不輸出。<br>
* 3.在讀到操作符時(shí),如果此操作符優(yōu)先級(jí)小于或等于此時(shí)棧頂操作符,則將棧中元素彈出直至(1)遇到左括號(hào)或者(2)棧頂元素為更低優(yōu)先級(jí)或者(3)
* 棧為空為止。操作符中,'+''-'優(yōu)先級(jí)最低,'('')'優(yōu)先級(jí)最高。 <br>
* 4.如果讀到輸入的末尾,將棧元素彈出直到該棧變成空棧,將符號(hào)寫(xiě)到輸出中。
*
* @return
*/
private List<Item> infix2postfix(List<Item> infixes) {
List<Item> postfixes = new ArrayList<Item>();
Stack<Item> stack = new Stack<Item>();
for (Item item : infixes) {
if (item.isNumber()) {
postfixes.add(item);
} else if (item.isRightBracket()) {
// ) 右括號(hào),將棧中元素彈出直至左括號(hào),且左括號(hào)和右括號(hào)不加入到后綴表達(dá)式中
while (true) {
Item tmp = stack.pop();
if (tmp.isLeftBracket())
break;
postfixes.add(tmp);
}
} else if (item.isLeftBracket()) {
// ( 左括號(hào),將左括號(hào)入棧
stack.push(item);
} else {
// 當(dāng)前操作符為 +, -, *, /,
if (stack.isEmpty()) {
// 操作符棧為空,則將當(dāng)前操作符壓入棧
stack.push(item);
continue;
}
Item top = stack.peek();
if (top.isLeftBracket()) {
// 操作符棧頂為左括號(hào)(,則將當(dāng)前操作符壓入棧
stack.push(item);
continue;
}
if (item.getPriority() <= top.getPriority()) {
// 如果此操作符(+,-,*,/)優(yōu)先級(jí)小于或等于此時(shí)棧頂操作符
// 則將棧中元素彈出直至(1)遇到左括號(hào)或者(2)棧頂元素為更低優(yōu)先級(jí)或者(3)棧為空為止
// 并將彈出的元素加入后綴表達(dá)式中,將當(dāng)前操作符壓入棧中
while (true) {
Item tmp = stack.peek();
if (tmp.isLeftBracket() || tmp.getPriority() < item.getPriority()) {
break;
}
postfixes.add(tmp);
stack.pop();
if (stack.isEmpty())
break;
}
stack.push(item);
} else {
// 如果當(dāng)前操作符(+,-,*,/)優(yōu)先級(jí)大于此時(shí)棧頂操作符,則將當(dāng)前操作符壓入棧
stack.push(item);
}
}
}
// 如果棧中元素不為空,則將棧中元素全部彈出,加入后綴表達(dá)式中
while (!stack.isEmpty()) {
postfixes.add(stack.pop());
}
return postfixes;
}
/**
* 通過(guò)后綴表達(dá)式計(jì)算數(shù)值
* <p>
* 1. 從左到右遍歷表達(dá)式的每個(gè)數(shù)字和符號(hào),遇到是數(shù)字則進(jìn)棧,遇到是運(yùn)算符則將棧頂兩個(gè)元素出棧,進(jìn)行運(yùn)算并將運(yùn)算結(jié)果進(jìn)棧<br>
* 2. 遍歷完后綴表達(dá)式,此時(shí)棧中剩余的數(shù)字就是運(yùn)算結(jié)果
*
* @param postfixes
* @return
*/
private int calculateByPostfix(List<Item> postfixes) {
Stack<Integer> stack = new Stack<Integer>();
for (Item item : postfixes) {
if (item.isNumber()) {
stack.push(item.getNumber());
} else {
// 運(yùn)算符
int num1 = stack.pop();
int num2 = stack.pop();
int result;
if (item.isAdd()) {
result = num2 + num1;
} else if (item.isSub()) {
result = num2 - num1;
} else if (item.isMul()) {
result = num2 * num1;
} else if (item.isDiv()) {
result = num2 / num1;
} else {
throw new IllegalArgumentException("Operator invalid : " + item.value);
}
stack.push(result);
}
}
return stack.pop();
}
public static void main(String[] args) {
SimpleCalcutor calcutor = new SimpleCalcutor();
String calStr = "9+(3-1)*3+10/2";
int result = calcutor.calculate(calStr);
System.out.println(result);
}
}
源碼github地址:
SimpleCalculator