Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式流程詳解
一、棧
1、棧的基本介紹
棧是?個(gè)先?后出的有序列表。棧(stack)是限制線性表中元素的插?和刪除只能在線性表的同?端進(jìn)?的?種特殊線性表。允許插?和刪除的?端,為變化的?端,稱(chēng)為棧頂(Top),另?端為固定的?端,稱(chēng)為棧底(Bottom)。
根據(jù)棧的定義可知,最先放?棧中元素在棧底,最后放?的元素在棧頂,?刪除元素剛好相反,最后放?的元素最先刪除,最先放?的元素最后刪除。
2、棧的底層實(shí)現(xiàn)
(1)創(chuàng)建一個(gè)類(lèi),模擬棧
maxSize :棧的最大容量
top :表示棧頂
stack :數(shù)組用來(lái)存儲(chǔ)數(shù)據(jù)
public class Stacks { public int maxSize; public int top ; public int[] stack; //構(gòu)造器,傳入棧的最大容量 public Stacks(int maxSize) { this.maxSize = maxSize; //初始化棧頂?shù)奈恢脼?1,??? top = -1; //初始化數(shù)組,最大容量為棧的容量 stack = new int[maxSize]; } }
(2)判斷棧空和棧滿(mǎn)
??????? 棧滿(mǎn)
//因?yàn)榈讓邮菙?shù)組存儲(chǔ)數(shù)據(jù),所以索引從0開(kāi)始, //判斷條件為 top == maxSize - 1 public boolean isFull(){ return top == maxSize - 1; }
? ???/p>
public boolean isEmpty(){ return top == -1; }
(3)入棧操作
首先判斷是否棧滿(mǎn),棧滿(mǎn)后則不能繼續(xù)添加,先對(duì)棧頂進(jìn)行加一,然后再放入數(shù)據(jù)。
public void push(int data){ //判斷是否棧滿(mǎn) if (isFull()){ System.out.println("棧滿(mǎn),無(wú)法入棧"); return; } top++; stack[top] = data; }
(4)出棧操作
首先判斷???,出棧操作其實(shí)就是將top減一即可,return stack[top--]; 這樣操作是為了讓我們知道出棧的數(shù)據(jù)是什么。
public int pop(){ if (isEmpty()){ throw new RuntimeException("???,無(wú)法出棧!"); } //先出棧,后減減 return stack[top--]; }
(5)顯示棧數(shù)據(jù)
public void show(){ if (isEmpty()){ System.out.println("棧空,無(wú)法顯示!"); return; } for (int i = top ; i >= 0; i--){ System.out.printf("stack[%d] = %d\n", i , stack[i]); } }
二、中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式
1、拆解中綴表達(dá)式
首先將中綴表達(dá)式拆解成一個(gè)一個(gè)的字符,存放到集合中,方便后面我們將中綴轉(zhuǎn)后綴時(shí)的遍歷操作。
首先用split分割操作將原數(shù)據(jù)分割到數(shù)組中存放,然后用增強(qiáng)for循環(huán)遍歷并同時(shí)存放到創(chuàng)建好的stringList集合中。
public static List<String> endList(String s){ String[] s1 = s.split(""); List<String> stringList = new ArrayList<>(); for (String s2 : s1) { stringList.add(s2); } return stringList; }
補(bǔ)充運(yùn)算符優(yōu)先級(jí)的判斷
后面我們轉(zhuǎn)換成后綴表達(dá)式時(shí),需要判斷運(yùn)算符的優(yōu)先級(jí)。
public static int Calcu(String s){ char ch = s.charAt(0); if (ch == '-' || ch == '+'){ return 0; } else if (ch == '*' || ch == '/') { return 1; } return -1; }
2、中綴轉(zhuǎn)后綴的算法
- 初始化兩個(gè)棧:運(yùn)算符棧s1和儲(chǔ)存中間結(jié)果的棧s2
- 從左至右掃描中綴表達(dá)式
- 遇到操作數(shù)時(shí),將其壓s2
- 遇到運(yùn)算符時(shí), 比較其與s1棧頂運(yùn)算符的優(yōu)先級(jí)
?如果s1為空,或棧頂運(yùn)算符為左括號(hào)“(”,則直接將此運(yùn)算符入棧
?否則,若優(yōu)先級(jí)比棧項(xiàng)運(yùn)算符的高,也將運(yùn)算符壓入s1
?否則,將s1棧頂?shù)倪\(yùn)算符彈出并壓入到s2中 ,再次與s1中新的棧頂運(yùn)算符相比較
- 遇到括號(hào)時(shí):
? 如果是左括號(hào)“(”,則直接壓入s1
? 如果是右括號(hào)“)”,則依次彈出s1棧頂?shù)倪\(yùn)算符, 并壓入s2,直到遇到左括號(hào)為止,此時(shí)將這一對(duì)括號(hào)丟棄
- 重復(fù)步驟2至5,直到表達(dá)式的最右邊
- 將s1中剩余的運(yùn)算符依次彈出并壓入s2
- 依次彈出s2中的元素并輸出,結(jié)果的逆序即為中綴表達(dá)式對(duì)應(yīng)的后綴表達(dá)式
3、中綴轉(zhuǎn)后綴代碼解析
前面的算法說(shuō)到,首先創(chuàng)建兩個(gè)棧一個(gè)運(yùn)算符棧和一個(gè)中間結(jié)果棧,但是根據(jù)上面算法的介紹,中間結(jié)果棧沒(méi)有出棧操作,就是數(shù)據(jù)全部是存入,于是在寫(xiě)代碼的時(shí)候我們可以將中間結(jié)果棧換成集合來(lái)存放數(shù)據(jù)。
首先用增強(qiáng)for循環(huán)遍歷原數(shù)據(jù)集合,然后進(jìn)行判斷,如果是數(shù)字就放入右方的集合中,如果是運(yùn)算符就放入左方的符號(hào)棧中。
進(jìn)行運(yùn)算符判斷,如果是左括號(hào)“( ” 就直接放入符號(hào)棧中,如果是右括號(hào)“ )”,就取出符號(hào)棧棧頂?shù)姆?hào)放入集合中,直到遇到左括號(hào)“( ”,停止將棧頂?shù)姆?hào)放入集合中,此時(shí)將棧頂出棧也就是去掉括號(hào)。
然后繼續(xù)進(jìn)行遍歷放入數(shù)據(jù)和符號(hào),如果是符號(hào),就與符號(hào)棧的棧頂?shù)姆?hào)進(jìn)行比較,要放入運(yùn)算符的運(yùn)算級(jí)如果小于等于棧頂運(yùn)算符的運(yùn)算級(jí),就將棧頂?shù)倪\(yùn)算符放入集合中,但下面的圖中,運(yùn)算符為括號(hào),所以不用管,因?yàn)槔ㄌ?hào)有單獨(dú)的判斷條件,所以直接放入。
遇到右括號(hào)又繼續(xù)重復(fù)前面的操作。
放入運(yùn)算符的優(yōu)先級(jí)小于等于棧頂運(yùn)算符的優(yōu)先級(jí),于是將棧頂?shù)倪\(yùn)算符放入集合中,然后放入的運(yùn)算符繼續(xù)放入符號(hào)棧中。
最后循環(huán)結(jié)束,將符號(hào)棧中的運(yùn)算符依次放入到集合中。
public static List<String> MiddleToEndExpress(List<String> strings){ //創(chuàng)建棧,存放運(yùn)算符 Stack<String> operStack = new Stack<>(); //因?yàn)檫@個(gè)棧不需要出棧,所以使用集合 List<String> sumList = new ArrayList<>(); for (String s : strings) { //判斷是否是數(shù)據(jù) if (s.matches("\\d+")){ sumList.add(s);//是數(shù)據(jù)直接加入 }else if (s.equals("(")){//判斷是否是左括號(hào) operStack.push(s);//是,直接放入符號(hào)棧 }else if (s.equals(")")){//判斷是否是右括號(hào) while (!operStack.peek().equals("(")){//如果棧頂是左括號(hào),退出循環(huán) sumList.add(operStack.pop());//不是左括號(hào),就將棧頂?shù)姆?hào)依次放入集合 } //循環(huán)結(jié)束,表示棧頂是左括號(hào),把左括號(hào)去掉,就去掉了一對(duì)括號(hào) operStack.pop(); }else {//前面的判斷都不是,那就是運(yùn)算符 //如果符號(hào)棧為空,并且運(yùn)算符小于等于棧頂?shù)倪\(yùn)算符優(yōu)先級(jí) while (operStack.size() != 0 && Calcu(s) <= Calcu(operStack.peek())){ //就將棧頂?shù)倪\(yùn)算符放入集合中 sumList.add(operStack.pop()); } //然后將符號(hào)放入符號(hào)棧中 operStack.push(s); } } //遍歷結(jié)束,將符號(hào)棧剩余的符號(hào)依次取出放入集合中 while (operStack.size() != 0){ sumList.add(operStack.pop()); } //最后將集合返回 return sumList; }
最后結(jié)果為:結(jié)果中不能含括號(hào),否則轉(zhuǎn)換錯(cuò)誤!
4、對(duì)后綴表達(dá)式進(jìn)行計(jì)算
前面我們已經(jīng)將中綴轉(zhuǎn)成后綴表達(dá)式了,那么我們只需要直接計(jì)算了,首先還是遍歷我們的集合(存放后綴表達(dá)式的)將數(shù)據(jù)暫時(shí)放入棧中方便我們操作,然后在遍歷過(guò)程中進(jìn)行判斷,如果是數(shù)據(jù)就直接放入棧中,如果是運(yùn)算符就從棧中取出兩個(gè)數(shù)據(jù)進(jìn)行運(yùn)算,運(yùn)算結(jié)果又放入棧中,直到棧中只存在一個(gè)數(shù)據(jù)時(shí),就是最后的運(yùn)算結(jié)果。
public static int endCalculator(List<String> stringList){ //創(chuàng)建棧,存放數(shù)據(jù) Stack<String> dataStack = new Stack<>(); //循環(huán)遍歷集合 for (String s : stringList) { //正則表達(dá)式判斷是否是數(shù)據(jù),如果是,就放入棧中 if (s.matches("\\d+")){ dataStack.push(s); }else {//否則就是運(yùn)算符 //取出兩個(gè)數(shù)據(jù) int num1 = Integer.parseInt(dataStack.pop()); int num2 = Integer.parseInt(dataStack.pop()); //存放運(yùn)算結(jié)果的變量 int res = 0; //判斷運(yùn)算符繼續(xù)相應(yīng)的運(yùn)算 if (s.equals("+")){ res = num1 + num2; }else if (s.equals("-")) { res = num2 - num1; }else if (s.equals("*")) { res = num1 * num2; }else if (s.equals("/")) { res = num2 / num1; }else { throw new RuntimeException("運(yùn)算符異常!"); } //運(yùn)算過(guò)后將結(jié)果又放入棧中 dataStack.push("" + res); } } //最后返回棧中唯一的數(shù)據(jù)既是結(jié)果 return Integer.parseInt(dataStack.pop()); }
到此這篇關(guān)于Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式流程詳解的文章就介紹到這了,更多相關(guān)Java中綴表達(dá)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文帶你學(xué)會(huì)Java網(wǎng)絡(luò)編程
網(wǎng)絡(luò)編程是指編寫(xiě)運(yùn)行在多個(gè)設(shè)備(計(jì)算機(jī))的程序,這些設(shè)備都通過(guò)網(wǎng)絡(luò)連接起來(lái)。這篇文章將帶大家深入了解一下Java的網(wǎng)絡(luò)編程,需要的可以了解一下2022-08-08Spring如何集成ibatis項(xiàng)目并實(shí)現(xiàn)dao層基類(lèi)封裝
這篇文章主要介紹了Spring如何集成ibatis項(xiàng)目并實(shí)現(xiàn)dao層基類(lèi)封裝,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09java中的FileReader和FileWriter讀寫(xiě)流
這篇文章主要介紹了java中的FileReader和FileWriter讀寫(xiě)流,在java中對(duì)數(shù)據(jù)輸入輸出的操作陳作為流我們對(duì)不同的文件進(jìn)行操作,或者對(duì)操作文件進(jìn)行輸入和輸出時(shí)所用的流都是不同的,因此在java.io的包下存在很多流的類(lèi)或者接口提供給我們對(duì)應(yīng)的操作,需要的朋友可以參考下2023-10-10Mybatis + js 實(shí)現(xiàn)下拉列表二級(jí)聯(lián)動(dòng)效果
這篇文章給大家介紹基于Mybatis + js 實(shí)現(xiàn)下拉列表二級(jí)聯(lián)動(dòng)效果,實(shí)現(xiàn)代碼分為前端界面實(shí)現(xiàn)和后端處理方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-06-06JavaWeb之Servlet注冊(cè)頁(yè)面的實(shí)現(xiàn)示例
注冊(cè)頁(yè)面是很多網(wǎng)站都會(huì)是使用的到,本文主要介紹了JavaWeb之Servlet注冊(cè)頁(yè)面的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04解決啟用 Spring-Cloud-OpenFeign 配置可刷新項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題
這篇文章主要介紹了解決啟用 Spring-Cloud-OpenFeign 配置可刷新項(xiàng)目無(wú)法啟動(dòng)的問(wèn)題,本文重點(diǎn)給大家介紹Spring-Cloud-OpenFeign的原理及問(wèn)題解決方法,需要的朋友可以參考下2021-10-10SpringBoot如何使用p6spy監(jiān)控?cái)?shù)據(jù)庫(kù)
這篇文章主要介紹了SpringBoot如何使用p6spy監(jiān)控?cái)?shù)據(jù)庫(kù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01