前缀、中缀、后缀表达式及其相互转化的Java实现
生活随笔
收集整理的這篇文章主要介紹了
前缀、中缀、后缀表达式及其相互转化的Java实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、中綴表達式轉換為前綴、后綴表達式 給個中綴表達式:a+b*c-(d+e) 首先根據運算符的優先級給所有運算單位加括號:((a+(b*c))-(d+e)) 將運算符號移動到對應括號的前面然后去掉所有括號就轉換為前綴表達式: -( +(a *(bc)) +(de)) -> ?-+a*bc+de 將運算符號移動到對應括號的后面然后去掉所有括號就轉換為后綴表達式: ((a(bc)* )+ (de)+ )- ?-> ??abc*+de+-
二、前綴表達式和后綴表達式的計算 前綴表達式的計算:從右至左掃描表達式,遇到數字的時候將數字入棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應運算(棧頂元素op次頂元素),并將結果入棧,重復該操作直到表達式最左端,最后算出的值即為表達式的結果。 后綴表達式的計算:從左至右掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(次頂元素 op 棧頂元素),并將結果入棧;重復上述過程直到表達式最右端,最后運算得出的值即為表達式的結果。 注意:這里都是前面元素op后面元素,但是因為前綴表達式在計算的時候是后面元素先入棧,所以是棧頂元素op次頂元素;后綴表達式是前面元素先入棧,所以是次頂元素op棧頂元素。
三、將中綴表達式轉換為前綴表達式 遵循以下步驟:
(1) 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
(2) 從右至左掃描中綴表達式;
(3) 遇到操作數時,將其壓入S2;
(4) 遇到運算符時,比較其與S1棧頂運算符的優先級:
(4-1) 如果S1為空,或棧頂運算符為右括號“)”,則直接將此運算符入棧;
(4-2) 否則,若優先級比棧頂運算符的較高或相等,也將運算符壓入S1;
(4-3) 否則,將S1棧頂的運算符彈出并壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算符相比較;
(5) 遇到括號時:
(5-1) 如果是右括號“)”,則直接壓入S1;
(5-2) 如果是左括號“(”,則依次彈出S1棧頂的運算符,并壓入S2,直到遇到右括號為止,此時將這一對括號丟棄;
(6) 重復步驟(2)至(5),直到表達式的最左邊;
(7) 將S1中剩余的運算符依次彈出并壓入S2;
(8) 依次彈出S2中的元素并輸出,結果即為中綴表達式對應的前綴表達式。
例如,將中綴表達式“1+((2+3)×4)-5”轉換為前綴表達式的過程如下:
因此結果為“- + 1 × + 2 3 4 5”。
四、后綴表達式轉換為中綴表達式 與轉換為前綴表達式相似,遵循以下步驟:
(1) 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
(2) 從左至右掃描中綴表達式;
(3) 遇到操作數時,將其壓入S2;
(4) 遇到運算符時,比較其與S1棧頂運算符的優先級:
(4-1) 如果S1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
(4-2) 否則,若優先級比棧頂運算符的高,也將運算符壓入S1(注意轉換為前綴表達式時是優先級較高或相同,而這里則不包括相同的情況);
(4-3) 否則,將S1棧頂的運算符彈出并壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算符相比較;
(5) 遇到括號時:
(5-1) 如果是左括號“(”,則直接壓入S1;
(5-2) 如果是右括號“)”,則依次彈出S1棧頂的運算符,并壓入S2,直到遇到左括號為止,此時將這一對括號丟棄;
(6) 重復步驟(2)至(5),直到表達式的最右邊;
(7) 將S1中剩余的運算符依次彈出并壓入S2;
(8) 依次彈出S2中的元素并輸出,結果的逆序即為中綴表達式對應的后綴表達式(轉換為前綴表達式時不用逆序)。
例如,將中綴表達式“1+((2+3)×4)-5”轉換為后綴表達式的過程如下:
因此結果為“1 2 3 + 4 × + 5 -”(注意需要逆序輸出)。
五、編程實現 String midToPost(String midSeq){Stack<Character> S1 = new Stack<Character>();Stack<Character> S2 = new Stack<Character>();int len = midSeq.length();int index = 0;while(index < len){char c = midSeq.charAt(index);switch(c){case '(':S1.push(c);break;case ')':while(S1.peek() != '(')S2.push(S1.pop());S1.pop();break;case '+':case '-':while(!S1.empty() && S1.peek() != '(')S2.push(S1.pop());S1.push(c);break;case '*':case '/':while(!S1.empty() && S1.peek().toString().matches("[*/]"))S2.push(S1.pop());S1.push(c);break;default:S2.push(c);}index++;}while(!S1.empty())S2.push(S1.pop());Iterator<Character> iter = S2.iterator();StringBuffer postSeq = new StringBuffer();while(iter.hasNext())postSeq.append(iter.next());return postSeq.toString(); }String midToPre(String midSeq){Stack<Character> S1 = new Stack<>(); //S1用來存放臨時運算符Stack<Character> S2 = new Stack<Character>(); //S2用來存放最后結果int len = midSeq.length();int index = len - 1;while(index >= 0){char c = midSeq.charAt(index);switch(c){case ')':S1.push(c);break;case '(':while(S1.peek() != ')'){S2.push(S1.pop());}S1.pop();break;case '*':case '/':S1.push(c);break;case '+':case '-':if(S1.empty() || S1.peek().toString().matches("[+-]"))S1.push(c);else{while(!S1.empty() && S1.peek().toString().matches("[*/]")){S2.push(S1.pop());}S1.push(c);}break;default:S2.push(c);}index--;}while(!S1.empty())S2.push(S1.pop());StringBuffer preSeq = new StringBuffer();Iterator<Character> iter = S2.iterator();while(iter.hasNext())preSeq.append(iter.next());preSeq = preSeq.reverse();return preSeq.toString(); }
參考資料: http://blog.csdn.net/antineutrino/article/details/6763722 http://blog.csdn.net/sgbfblog/article/details/8001651
二、前綴表達式和后綴表達式的計算 前綴表達式的計算:從右至左掃描表達式,遇到數字的時候將數字入棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應運算(棧頂元素op次頂元素),并將結果入棧,重復該操作直到表達式最左端,最后算出的值即為表達式的結果。 后綴表達式的計算:從左至右掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(次頂元素 op 棧頂元素),并將結果入棧;重復上述過程直到表達式最右端,最后運算得出的值即為表達式的結果。 注意:這里都是前面元素op后面元素,但是因為前綴表達式在計算的時候是后面元素先入棧,所以是棧頂元素op次頂元素;后綴表達式是前面元素先入棧,所以是次頂元素op棧頂元素。
三、將中綴表達式轉換為前綴表達式 遵循以下步驟:
(1) 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
(2) 從右至左掃描中綴表達式;
(3) 遇到操作數時,將其壓入S2;
(4) 遇到運算符時,比較其與S1棧頂運算符的優先級:
(4-1) 如果S1為空,或棧頂運算符為右括號“)”,則直接將此運算符入棧;
(4-2) 否則,若優先級比棧頂運算符的較高或相等,也將運算符壓入S1;
(4-3) 否則,將S1棧頂的運算符彈出并壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算符相比較;
(5) 遇到括號時:
(5-1) 如果是右括號“)”,則直接壓入S1;
(5-2) 如果是左括號“(”,則依次彈出S1棧頂的運算符,并壓入S2,直到遇到右括號為止,此時將這一對括號丟棄;
(6) 重復步驟(2)至(5),直到表達式的最左邊;
(7) 將S1中剩余的運算符依次彈出并壓入S2;
(8) 依次彈出S2中的元素并輸出,結果即為中綴表達式對應的前綴表達式。
例如,將中綴表達式“1+((2+3)×4)-5”轉換為前綴表達式的過程如下:
| 掃描到的元素 | S2(棧底->棧頂) | S1 (棧底->棧頂) | 說明 |
| 5 | 5 | 空 | 數字,直接入棧 |
| - | 5 | - | S1為空,運算符直接入棧 |
| ) | 5 | - ) | 右括號直接入棧 |
| 4 | 5 4 | - ) | 數字直接入棧 |
| × | 5 4 | - ) × | S1棧頂是右括號,直接入棧 |
| ) | 5 4 | - ) × ) | 右括號直接入棧 |
| 3 | 5 4 3 | - ) × ) | 數字 |
| + | 5 4 3 | - ) × ) + | S1棧頂是右括號,直接入棧 |
| 2 | 5 4 3 2 | - ) × ) + | 數字 |
| ( | 5 4 3 2 + | - ) × | 左括號,彈出運算符直至遇到右括號 |
| ( | 5 4 3 2 + × | - | 同上 |
| + | 5 4 3 2 + × | - + | 優先級與-相同,入棧 |
| 1 | 5 4 3 2 + × 1 | - + | 數字 |
| 到達最左端 | 5 4 3 2 + × 1 + - | 空 | S1中剩余的運算符 |
因此結果為“- + 1 × + 2 3 4 5”。
四、后綴表達式轉換為中綴表達式 與轉換為前綴表達式相似,遵循以下步驟:
(1) 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
(2) 從左至右掃描中綴表達式;
(3) 遇到操作數時,將其壓入S2;
(4) 遇到運算符時,比較其與S1棧頂運算符的優先級:
(4-1) 如果S1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
(4-2) 否則,若優先級比棧頂運算符的高,也將運算符壓入S1(注意轉換為前綴表達式時是優先級較高或相同,而這里則不包括相同的情況);
(4-3) 否則,將S1棧頂的運算符彈出并壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算符相比較;
(5) 遇到括號時:
(5-1) 如果是左括號“(”,則直接壓入S1;
(5-2) 如果是右括號“)”,則依次彈出S1棧頂的運算符,并壓入S2,直到遇到左括號為止,此時將這一對括號丟棄;
(6) 重復步驟(2)至(5),直到表達式的最右邊;
(7) 將S1中剩余的運算符依次彈出并壓入S2;
(8) 依次彈出S2中的元素并輸出,結果的逆序即為中綴表達式對應的后綴表達式(轉換為前綴表達式時不用逆序)。
例如,將中綴表達式“1+((2+3)×4)-5”轉換為后綴表達式的過程如下:
| 掃描到的元素 | S2(棧底->棧頂) | S1 (棧底->棧頂) | 說明 |
| 1 | 1 | 空 | 數字,直接入棧 |
| + | 1 | + | S1為空,運算符直接入棧 |
| ( | 1 | + ( | 左括號,直接入棧 |
| ( | 1 | + ( ( | 同上 |
| 2 | 1 2 | + ( ( | 數字 |
| + | 1 2 | + ( ( + | S1棧頂為左括號,運算符直接入棧 |
| 3 | 1 2 3 | + ( ( + | 數字 |
| ) | 1 2 3 + | + ( | 右括號,彈出運算符直至遇到左括號 |
| × | 1 2 3 + | + ( × | S1棧頂為左括號,運算符直接入棧 |
| 4 | 1 2 3 + 4 | + ( × | 數字 |
| ) | 1 2 3 + 4 × | + | 右括號,彈出運算符直至遇到左括號 |
| - | 1 2 3 + 4 × + | - | -與+優先級相同,因此彈出+,再壓入- |
| 5 | 1 2 3 + 4 × + 5 | - | 數字 |
| 到達最右端 | 1 2 3 + 4 × + 5 - | 空 | S1中剩余的運算符 |
因此結果為“1 2 3 + 4 × + 5 -”(注意需要逆序輸出)。
五、編程實現 String midToPost(String midSeq){Stack<Character> S1 = new Stack<Character>();Stack<Character> S2 = new Stack<Character>();int len = midSeq.length();int index = 0;while(index < len){char c = midSeq.charAt(index);switch(c){case '(':S1.push(c);break;case ')':while(S1.peek() != '(')S2.push(S1.pop());S1.pop();break;case '+':case '-':while(!S1.empty() && S1.peek() != '(')S2.push(S1.pop());S1.push(c);break;case '*':case '/':while(!S1.empty() && S1.peek().toString().matches("[*/]"))S2.push(S1.pop());S1.push(c);break;default:S2.push(c);}index++;}while(!S1.empty())S2.push(S1.pop());Iterator<Character> iter = S2.iterator();StringBuffer postSeq = new StringBuffer();while(iter.hasNext())postSeq.append(iter.next());return postSeq.toString(); }String midToPre(String midSeq){Stack<Character> S1 = new Stack<>(); //S1用來存放臨時運算符Stack<Character> S2 = new Stack<Character>(); //S2用來存放最后結果int len = midSeq.length();int index = len - 1;while(index >= 0){char c = midSeq.charAt(index);switch(c){case ')':S1.push(c);break;case '(':while(S1.peek() != ')'){S2.push(S1.pop());}S1.pop();break;case '*':case '/':S1.push(c);break;case '+':case '-':if(S1.empty() || S1.peek().toString().matches("[+-]"))S1.push(c);else{while(!S1.empty() && S1.peek().toString().matches("[*/]")){S2.push(S1.pop());}S1.push(c);}break;default:S2.push(c);}index--;}while(!S1.empty())S2.push(S1.pop());StringBuffer preSeq = new StringBuffer();Iterator<Character> iter = S2.iterator();while(iter.hasNext())preSeq.append(iter.next());preSeq = preSeq.reverse();return preSeq.toString(); }
參考資料: http://blog.csdn.net/antineutrino/article/details/6763722 http://blog.csdn.net/sgbfblog/article/details/8001651
?
總結
以上是生活随笔為你收集整理的前缀、中缀、后缀表达式及其相互转化的Java实现的全部內容,希望文章能夠幫你解決所遇到的問題。