Java數(shù)據(jù)結(jié)構(gòu)之棧與綜合計(jì)算器的實(shí)現(xiàn)
1.棧
1.1 棧的簡(jiǎn)介
棧(stack)是具有 先進(jìn)后出 特性的有序列表。即限制線性表中的元素的插入和刪除只能在同一端。
- 棧頂:允許插入和刪除的一端
- 棧底:固定的一端
因此,最先放入棧的元素在棧底,最后放入的元素在棧頂。當(dāng)刪除(出棧)的時(shí)候,正好相反,棧頂元素先刪除,即最后放入的元素。
出棧入棧的示意圖如下:
Top初始指向最底端,在數(shù)組模擬時(shí),初始一般為-1。進(jìn)行入棧操作時(shí),每進(jìn)一個(gè)元素,Top都會(huì)自增,指向棧頂元素。出棧則是入棧的逆過(guò)程。
1.2 使用數(shù)組模擬棧
因?yàn)闂5膶?shí)現(xiàn)較為簡(jiǎn)單,這里直接展示代碼,詳細(xì)實(shí)現(xiàn)思路可以見(jiàn)代碼注釋。
ArrayStack.java
/** * @author 興趣使然黃小黃 * @version 1.0 * 用數(shù)組去模擬棧 */ @SuppressWarnings({"all"}) public class ArrayStack { private int maxSize; //棧的大小 private int[] stack; //用數(shù)組模擬棧 private int top = -1; //指向棧頂 //構(gòu)造器 public ArrayStack(int maxSize){ this.maxSize = maxSize; this.stack = new int[this.maxSize]; } //判斷棧滿 public boolean isFull(){ return top == maxSize - 1; } //判斷??? public boolean isEmpty(){ return top == -1; } //入棧 public void push(int value){ //判斷是否滿 if (isFull()){ System.out.println("棧已滿,無(wú)法入棧!"); return; } //入棧操作 stack[++top] = value; } //出棧 public int pop(){ //先判斷是否為空 if (isEmpty()){ throw new RuntimeException("當(dāng)前棧已空,無(wú)法出棧!"); } //出棧操作 int value = stack[top]; top--; return value; } //遍歷 public void showStack(){ //從棧頂開(kāi)始遍歷 if (isEmpty()){ System.out.println("???); } for (int i = top; i >= 0; i--){ System.out.printf("stack[%d] = %d\n", i, stack[i]); } } }
1.3 棧的測(cè)試
測(cè)試代碼及結(jié)果如下:
import java.util.Scanner; /** * @author 興趣使然黃小黃 * @version 1.0 * 測(cè)試棧 */ @SuppressWarnings({"all"}) public class ArrayStackDemo { public static void main(String[] args) { ArrayStack arrayStack = new ArrayStack(4); String key = ""; boolean loop = true; //控制菜單 Scanner scanner = new Scanner(System.in); while (loop){ System.out.println("show 顯示棧"); System.out.println("exit 退出棧"); System.out.println("pop 出棧"); System.out.println("push 入棧"); System.out.println("請(qǐng)輸入:"); key = scanner.next(); switch (key){ case "show": arrayStack.showStack(); break; case "exit": scanner.close(); loop = false; break; case "push": System.out.println("請(qǐng)輸入要存入的值: "); int value = scanner.nextInt(); arrayStack.push(value); break; case "pop": try { System.out.println(arrayStack.pop() + "出棧"); } catch (Exception e) { e.printStackTrace(); } break; default: System.out.println("輸入有誤,請(qǐng)重新輸入!"); break; } } System.out.println("程序結(jié)束..."); } }
實(shí)現(xiàn)結(jié)果:
show 顯示棧
exit 退出棧
pop 出棧
push 入棧
請(qǐng)輸入:
push
請(qǐng)輸入要存入的值:
1
show 顯示棧
exit 退出棧
pop 出棧
push 入棧
請(qǐng)輸入:
push
請(qǐng)輸入要存入的值:
2
show 顯示棧
exit 退出棧
pop 出棧
push 入棧
請(qǐng)輸入:
pop
2出棧
show 顯示棧
exit 退出棧
pop 出棧
push 入棧
請(qǐng)輸入:
show
stack[0] = 1
show 顯示棧
exit 退出棧
pop 出棧
push 入棧
請(qǐng)輸入:
exit
程序結(jié)束...
Process finished with exit code 0
2.綜合計(jì)算器的實(shí)現(xiàn)
2.1 需求簡(jiǎn)介
簡(jiǎn)單計(jì)算器的實(shí)現(xiàn)旨模擬計(jì)算機(jī)計(jì)算表達(dá)式。
例: 輸入:3+2*6-2
計(jì)算機(jī)可以通過(guò)讀取字符串,判斷數(shù)字或者符號(hào),以及算術(shù)符號(hào)的優(yōu)先級(jí)進(jìn)行計(jì)算操作,返回正確的結(jié)果。
輸出:13
2.2 詳細(xì)思路及分步圖解
思路如下:
1.通過(guò)一個(gè)index索引值來(lái) 遍歷算式表達(dá)式;
2.使用兩個(gè)棧來(lái)模擬。一個(gè)為數(shù)字棧,一個(gè)為符號(hào)棧;
3.如果為數(shù)字,則入數(shù)字棧;
4.如果為符號(hào),則分以下情況:
- 符號(hào)棧為空:直接入符號(hào)棧;
- 符號(hào)棧不為空:將當(dāng)前符號(hào)與符號(hào)棧中的棧頂元素進(jìn)行優(yōu)先級(jí)比較。 如果當(dāng)前操作符號(hào)優(yōu)先級(jí)小于棧頂元素,則取出符號(hào)棧的棧頂元素,并從數(shù)字棧取出兩個(gè)數(shù)進(jìn)行運(yùn)算,得到數(shù)字結(jié)果入數(shù)字棧,并將當(dāng)前操作符入符號(hào)棧。如果當(dāng)前的操作符的優(yōu)先級(jí)大于符號(hào)棧棧頂元素,則直接入符號(hào)棧。
5.當(dāng)表達(dá)式掃描完畢,則順序從數(shù)字棧和符號(hào)棧取出對(duì)應(yīng)的數(shù)字和符號(hào)進(jìn)行計(jì)算,將結(jié)果繼續(xù)存入數(shù)字棧,直到符號(hào)棧為空;
6.此時(shí),數(shù)字棧只剩下了計(jì)算的結(jié)果, 該結(jié)果即為表達(dá)式的值。
以3+2*6-2為例:
先將3入數(shù)字棧
+
入符號(hào)棧
2入數(shù)字棧
遇到了 *
,將其與符號(hào)棧的棧頂元素 +
比較,*
的優(yōu)先級(jí)更高,因此,*
直接入符號(hào)棧
6 入數(shù)字棧
-
與符號(hào)棧棧頂 *
進(jìn)行比較,-
優(yōu)先級(jí)低,因此,將符號(hào)棧的棧頂 *
出棧。數(shù)字棧依次出棧兩個(gè)數(shù)6、2,計(jì)算2*6的值為12,并將12入數(shù)字棧,當(dāng)前操作符-
入符號(hào)棧
2 入棧,至此,表達(dá)式遍歷完成。下面將要開(kāi)始依次取值計(jì)算,直到符號(hào)棧為空。
將2、12從數(shù)字棧取出,將-
從符號(hào)棧取出,計(jì)算12-2的值10,入數(shù)字棧
依次將10、3從數(shù)字棧出棧,+
從符號(hào)棧取出,并計(jì)算3+10的值為13,13入數(shù)字棧。此時(shí),符號(hào)棧為空,運(yùn)算到此為止,13即為表達(dá)式的結(jié)果。
2.3 完整代碼及測(cè)試
在實(shí)際編碼過(guò)程中,如果遇到數(shù)字需要繼續(xù)判斷下一位是否為數(shù)字,如果為數(shù)字,則需要將這幾個(gè)字符進(jìn)行拼接字符串的操作,再存入數(shù)字棧中。即,需要對(duì)多位數(shù)進(jìn)行處理。
為了實(shí)現(xiàn)方便,這里我們使用Java自帶的stack類。
import java.util.Scanner; import java.util.Stack; /** * @author 興趣使然黃小黃 * @version 1.0 * 簡(jiǎn)單計(jì)算器實(shí)現(xiàn) */ @SuppressWarnings({"all"}) public class Calculator { public static void main(String[] args) { //接收表達(dá)式 System.out.println("請(qǐng)輸入表達(dá)式: "); Scanner scanner = new Scanner(System.in); String expression = scanner.next(); //創(chuàng)建一個(gè)數(shù)棧 一個(gè)符號(hào)棧 Stack<Integer> numStack = new Stack<>(); Stack<Integer> operStack = new Stack<>(); //定義變量 int index = 0; //用于掃描 int num1 = 0; int num2 = 0; int oper = 0; int res = 0; char ch = ' '; //每次掃描的char保存 String keepNum = ""; //用于保存多位數(shù)字進(jìn)行拼接 //掃描計(jì)算 while (true){ //依次得到expression每一個(gè)字符 ch = expression.substring(index, index+1).charAt(0); //判斷ch進(jìn)行相應(yīng)的處理 if (isOper(ch)){ //如果是運(yùn)算符 if (operStack.isEmpty()){ //判斷當(dāng)前的符號(hào)棧是否為空,若為空直接入棧 operStack.push((int)ch); }else { //符號(hào)棧不為空 //若當(dāng)前操作符優(yōu)先級(jí)小于等于棧中的操作符 if (priority(ch) <= priority(operStack.peek())){ num1 = numStack.pop(); num2 = numStack.pop(); oper = operStack.pop(); res = cal(num1, num2, oper); //將運(yùn)算結(jié)果入數(shù)棧 numStack.push(res); //將當(dāng)前的操作符入符號(hào)棧 operStack.push((int) ch); }else { operStack.push((int) ch); } } }else { //如果是數(shù)字直接入數(shù)棧 //需要考慮多位數(shù)的情況 //如果當(dāng)前位置為數(shù)字,則繼續(xù)向后看,直到為符號(hào)或者遍歷完成為止 //已經(jīng)查看的數(shù)字進(jìn)行字符串拼接,即為正確的數(shù)字 keepNum += ch; //如果已經(jīng)到末尾,則直接入棧 if (index == expression.length()-1){ numStack.push(Integer.parseInt(keepNum)); }else { //判斷下一個(gè)字符是否為數(shù)字,若是則繼續(xù)掃描,不是則直接入棧 if (isOper(expression.substring(index+1, index+2).charAt(0))){ numStack.push(Integer.parseInt(keepNum)); //1的ascII碼為49,而ch為字符 keepNum = ""; } } } //index+1 并判斷是否掃描完畢 index++; if (index >= expression.length()){ break; } } //表達(dá)式掃描完畢過(guò)后,順序的從數(shù)棧和符號(hào)棧取出對(duì)應(yīng)的數(shù)字和符號(hào)進(jìn)行運(yùn)算 //最后數(shù)棧只剩的一個(gè)數(shù)字為結(jié)果 //也可以判斷符號(hào)棧是否為空,如果為空則說(shuō)明數(shù)棧只剩一個(gè)數(shù) while (numStack.size() > 1){ num1 = numStack.pop(); num2 = numStack.pop(); oper = operStack.pop(); res = cal(num1, num2, oper); numStack.push(res); } //打印結(jié)果 System.out.println("結(jié)果: " + numStack.pop()); } //返回運(yùn)算符號(hào)的優(yōu)先級(jí),返回?cái)?shù)字越大,優(yōu)先級(jí)越大 public static int priority(int operation){ if (operation == '*' || operation == '/'){ return 1; }else if (operation == '+' || operation == '-'){ return 0; }else { return -1; } } //判斷是否為運(yùn)算符 public static boolean isOper(char val){ return val == '+' || val == '-' || val == '/' || val == '*'; } //計(jì)算方法 public static int cal(int num1, int num2, int operation){ int res = 0; //存放返回的結(jié)果 switch (operation){ case '+': res = num1 + num2; break; case '-': res = num2 - num1; break; case '*': res = num1 * num2; break; case '/': res = num2 / num1; break; default: break; } return res; } }
實(shí)現(xiàn)結(jié)果:
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之棧與綜合計(jì)算器的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java棧 綜合計(jì)算器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
繼承JpaRepository后,找不到findOne()方法的解決
這篇文章主要介紹了繼承JpaRepository后,找不到findOne()方法的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java基于Session登錄驗(yàn)證的實(shí)現(xiàn)示例
基于Session的登錄驗(yàn)證方式是最簡(jiǎn)單的一種登錄校驗(yàn)方式,本文主要介紹了Java基于Session登錄驗(yàn)證的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02springboot mybatis-plus實(shí)現(xiàn)登錄接口
本文主要介紹了springboot mybatis-plus實(shí)現(xiàn)登錄接口,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問(wèn)題
這篇文章主要介紹了JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03Spring Boot+Nginx實(shí)現(xiàn)大文件下載功能
相信很多小伙伴,在日常開(kāi)放中都會(huì)遇到大文件下載的情況,大文件下載方式也有很多,比如非常流行的分片下載、斷點(diǎn)下載;當(dāng)然也可以結(jié)合Nginx來(lái)實(shí)現(xiàn)大文件下載,在中小項(xiàng)目非常適合使用,這篇文章主要介紹了Spring Boot結(jié)合Nginx實(shí)現(xiàn)大文件下載,需要的朋友可以參考下2024-05-05FactoryBean?BeanFactory方法使用示例詳解講解
這篇文章主要為大家介紹了FactoryBean?BeanFactory方法使用示例詳解講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12