Java數(shù)據(jù)結(jié)構(gòu)之棧與綜合計算器的實現(xiàn)
1.棧
1.1 棧的簡介
棧(stack)是具有 先進后出 特性的有序列表。即限制線性表中的元素的插入和刪除只能在同一端。
- 棧頂:允許插入和刪除的一端
- 棧底:固定的一端
因此,最先放入棧的元素在棧底,最后放入的元素在棧頂。當刪除(出棧)的時候,正好相反,棧頂元素先刪除,即最后放入的元素。
出棧入棧的示意圖如下:
Top初始指向最底端,在數(shù)組模擬時,初始一般為-1。進行入棧操作時,每進一個元素,Top都會自增,指向棧頂元素。出棧則是入棧的逆過程。

1.2 使用數(shù)組模擬棧
因為棧的實現(xiàn)較為簡單,這里直接展示代碼,詳細實現(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("當前棧已空,無法出棧!");
}
//出棧操作
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 詳細思路及分步圖解
思路如下:
1.通過一個index索引值來 遍歷算式表達式;
2.使用兩個棧來模擬。一個為數(shù)字棧,一個為符號棧;
3.如果為數(shù)字,則入數(shù)字棧;
4.如果為符號,則分以下情況:
- 符號棧為空:直接入符號棧;
- 符號棧不為空:將當前符號與符號棧中的棧頂元素進行優(yōu)先級比較。 如果當前操作符號優(yōu)先級小于棧頂元素,則取出符號棧的棧頂元素,并從數(shù)字棧取出兩個數(shù)進行運算,得到數(shù)字結(jié)果入數(shù)字棧,并將當前操作符入符號棧。如果當前的操作符的優(yōu)先級大于符號棧棧頂元素,則直接入符號棧。
5.當表達式掃描完畢,則順序從數(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ù)字棧,當前操作符- 入符號棧

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()){
//判斷當前的符號棧是否為空,若為空直接入棧
operStack.push((int)ch);
}else {
//符號棧不為空
//若當前操作符優(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);
//將當前的操作符入符號棧
operStack.push((int) ch);
}else {
operStack.push((int) ch);
}
}
}else {
//如果是數(shù)字直接入數(shù)棧
//需要考慮多位數(shù)的情況
//如果當前位置為數(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-08
springboot mybatis-plus實現(xiàn)登錄接口
本文主要介紹了springboot mybatis-plus實現(xiàn)登錄接口,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-11-11
JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問題
這篇文章主要介紹了JAVA構(gòu)造函數(shù)不能使用void關(guān)鍵字問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
Spring Boot+Nginx實現(xiàn)大文件下載功能
相信很多小伙伴,在日常開放中都會遇到大文件下載的情況,大文件下載方式也有很多,比如非常流行的分片下載、斷點下載;當然也可以結(jié)合Nginx來實現(xiàn)大文件下載,在中小項目非常適合使用,這篇文章主要介紹了Spring Boot結(jié)合Nginx實現(xiàn)大文件下載,需要的朋友可以參考下2024-05-05
FactoryBean?BeanFactory方法使用示例詳解講解
這篇文章主要為大家介紹了FactoryBean?BeanFactory方法使用示例詳解講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12

