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