1. 後綴表達式
後綴表達式,即爲逆波蘭表達式,其運算方法爲從左到右掃描表達式,當遇到符號時,取該符號前兩位數,使用前一個數運算後一個數,將結果放入剛纔兩個數的位置,運算的兩個數以及符號便去掉。由此得知,使用棧運算會很方便,下面會有完整的計算一個四則運算表達式的代碼
2. 思路分析
1.將字符串轉化爲list,目的是方便操作
2.簡歷一個符號棧與結果隊列,符號棧用於存儲遍歷得到的符號,隊列利用其先進先出的特性來記錄轉化後的後綴表達式
3.遍歷該list
3.1該元素爲數字,直接入結果隊列
3.2該元素爲符號
3.2.1棧爲空或者棧頂元素爲”(“,則將該元素直接入符號棧
3.2.2棧頂元素優先級小於該元素,則將該元素直接入符號棧
3.2.3如果不滿足以上條件,則將棧頂元素入結果隊列,並且從3.2.1繼續開始進行判斷
3.3遍歷list結束後,將棧中剩餘的元素依次加入結果隊列中,結果即爲對應的後綴表達式
3. 代碼實現
//本代碼包含: 中綴表達式轉化後綴表達式,計算後綴表達式
package stack;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
/**
* 逆波蘭計算器
*/
public class ReversePolish {
public static void main(String[] args) {
String s = "2*(16+8/4-5)+4";
ReversePolish reversePolish = new ReversePolish();
System.out.println(reversePolish.toReversePolish(stringToList(s)).toString());
System.out.println(reversePolish.calculate(reversePolish.toReversePolish(stringToList(s))));
}
private List<String> toReversePolish(List<String> list){
Stack<String> stack = new Stack<String>();
List<String> linkedList = new LinkedList<String>();
for (int i = 0; i < list.size(); i++){
String s = list.get(i);
int chk = check(s);
//如果當前元素爲符號
if (chk == 0){
//如果棧爲空或者棧頂元素爲( 直接壓入棧
if (stack.isEmpty() || "(".equals(stack.peek())){
stack.push(s);
continue;
}
//如果符號棧不爲空
//取當前符號的優先級
int a = compare(s);
//取棧頂元素的優先級
int b = compare(stack.peek());
//如果當前符號優先級大於棧頂元素優先級
if (a > b){
stack.push(s);
}else{//如果棧不爲空或棧頂不爲(或者當前符號不比棧頂元素優先級高
//繼續判斷棧是否爲空或者棧頂元素是否爲(
while (true){
if (stack.isEmpty() || "(".equals(stack.peek())){
stack.push(s);
break;
}
//繼續判斷棧頂元素與當前元素優先級
if (a > compare(stack.peek())){
linkedList.add(s);
break;
}
//如果不滿足以上條件,將棧頂元素加入結果隊列中,並且繼續循環
linkedList.add(stack.pop());
}
}
}else if (chk == 1){//如果當前元素爲( 則直接入棧
stack.push(s);
}else if (chk == 2){//如果當前元素爲) 則將棧頂一次加入結果隊列 直到棧頂爲(
while(true){
String top = stack.pop();
if ("(".equals(top)){//如果棧頂爲( 則結束循環 將這對括號丟棄
break;
}else {//棧頂不爲( 將棧頂元素加入到結果集中即可
linkedList.add(top);
}
}
}else{
linkedList.add(s);
}
}
//循環結束後,將棧中剩餘的元素依次入結果集
while(!stack.isEmpty()){
linkedList.add(stack.pop());
}
//返回隊列即爲後綴表達式
return linkedList;
}
private int compare(String s){
if ("+".equals(s) || "-".equals(s)){
return 1;
}else {
return 2;
}
}
private int check(String s){
if ("+".equals(s) || "-".equals(s) || "/".equals(s) || "*".equals(s)){
return 0;
}else if ("(".equals(s)){
return 1;
}else if (")".equals(s)){
return 2;
}else{
return 3;
}
}
private int calculate(List<String> list){
Stack<Integer> numStack = new Stack<Integer>();
for (int i = 0; i < list.size(); i++){
String s = list.get(i);
if (notNumber(s)){
int num1 = numStack.pop();
int num2 = numStack.pop();
if ("+".equals(s)){
numStack.push(num1 + num2);
}else if ("-".equals(s)){
numStack.push(num2 - num1);
}else if ("*".equals(s)){
numStack.push(num2 * num1);
}else if ("/".equals(s)){
numStack.push(num2 / num1);
}
}else {
numStack.push(Integer.parseInt(s));
}
}
return numStack.pop();
}
private boolean notNumber(String s){
return "+".equals(s) || "-".equals(s) || "*".equals(s) || "/".equals(s);
}
private static List<String> stringToList(String s){
List<String> res = new ArrayList<String>();
int i = 0;
while(i < s.length()){
char c = s.charAt(i);
//數字
if (c >= 48 && c <= 57){
String str = "";
while (i < s.length() && ((c = s.charAt(i)) >= 48 && (c <= 57)) ){
str = str + String.valueOf(c);
i++;
}
res.add(str);
}else{//符號
res.add(String.valueOf(c));
i++;
}
}
return res;
}
}
4. 後記
本文重點記錄思路,代碼較爲粗糙,太累了…以後有時間了再美化吧。