Java利用棧實(shí)現(xiàn)簡易計算器功能
利用棧實(shí)現(xiàn)一個簡易計算器(Java實(shí)現(xiàn)),供大家參考,具體內(nèi)容如下
一、思路分析
當(dāng)我們輸入一個類似于“7*2+100-5+3-4/2”的簡單中綴表達(dá)式時,我們的編譯器能夠利用我們所編寫的代碼將這個表達(dá)式掃描并計算出其結(jié)果
在這個表達(dá)式中主要有兩種元素,一種是數(shù)字,一種是符號,那么我們就需要創(chuàng)建兩個棧結(jié)構(gòu)存儲數(shù)據(jù)
- 數(shù)棧numStack:存放數(shù)
- 符號棧operStack:存放運(yùn)算符
1、首先我們需要定義一個index(索引),來遍歷我們的表達(dá)式
2、如果掃描到一個數(shù)字,就直接入數(shù)棧
3、如果掃描到一個運(yùn)算符,那就要分以下幾種情況:
? 3.1、如果當(dāng)前符號棧為空,就直接入棧
? 3.2、如果符號棧有運(yùn)算符,就需要進(jìn)行比較
? 如果當(dāng)前運(yùn)算符的優(yōu)先級小于或等于棧中的運(yùn)算符,就需要從數(shù)棧中pop出兩個數(shù),在符號棧中pop出一個符號,進(jìn)行運(yùn)算,得到結(jié)果,入數(shù)棧,然后將當(dāng)前的操作符入符號棧
? 如果當(dāng)前運(yùn)算符的優(yōu)先級大于棧中的運(yùn)算符,就直接入符號棧
4、當(dāng)表達(dá)式掃描完畢,就順序的從數(shù)棧和符號棧中pop出相應(yīng)的數(shù)和符號,并進(jìn)行計算
5、最后保留在數(shù)棧中的那個數(shù)字就是運(yùn)算的結(jié)果
二、代碼實(shí)現(xiàn)
package com.hsy.stack; public class Calculator { ? ? public static void main(String[] args) { ? ? ? ? //根據(jù)前面老師思路,完成表達(dá)式的運(yùn)算 ? ? ? ? String expression = "7*2+100-5+3-4/2";//如何處理多位數(shù)的問題? ? ? ? ? //創(chuàng)建兩個棧,數(shù)棧,一個符號棧 ? ? ? ? ArrayStack2 numStack = new ArrayStack2(10); ? ? ? ? ArrayStack2 operStack = new ArrayStack2(10); ? ? ? ? //定義需要的相關(guān)變量 ? ? ? ? int index = 0;//用于掃描 ? ? ? ? int num1 = 0; ? ? ? ? int num2 = 0; ? ? ? ? int oper = 0; ? ? ? ? int res = 0; ? ? ? ? char ch = ' '; //將每次掃描得到char保存到ch ? ? ? ? String keepNum = ""; //用于拼接 多位數(shù) ? ? ? ? //開始while循環(huán)的掃描expression ? ? ? ? while(true) { ? ? ? ? ? ? //依次得到expression 的每一個字符 ? ? ? ? ? ? ch = expression.substring(index, index+1).charAt(0); ? ? ? ? ? ? //判斷ch是什么,然后做相應(yīng)的處理 ? ? ? ? ? ? if(operStack.isOper(ch)) {//如果是運(yùn)算符 ? ? ? ? ? ? ? ? //判斷當(dāng)前的符號棧是否為空 ? ? ? ? ? ? ? ? if(!operStack.isEmpty()) { ? ? ? ? ? ? ? ? ? ? //如果符號棧有操作符,就進(jìn)行比較,如果當(dāng)前的操作符的優(yōu)先級小于或者等于棧中的操作符,就需要從數(shù)棧中pop出兩個數(shù), ? ? ? ? ? ? ? ? ? ? //在從符號棧中pop出一個符號,進(jìn)行運(yùn)算,將得到結(jié)果,入數(shù)棧,然后將當(dāng)前的操作符入符號棧 ? ? ? ? ? ? ? ? ? ? if(operStack.priority(ch) <= operStack.priority(operStack.peek())) { ? ? ? ? ? ? ? ? ? ? ? ? num1 = numStack.pop(); ? ? ? ? ? ? ? ? ? ? ? ? num2 = numStack.pop(); ? ? ? ? ? ? ? ? ? ? ? ? oper = operStack.pop(); ? ? ? ? ? ? ? ? ? ? ? ? res = numStack.cal(num1, num2, oper); ? ? ? ? ? ? ? ? ? ? ? ? //把運(yùn)算的結(jié)果如數(shù)棧 ? ? ? ? ? ? ? ? ? ? ? ? numStack.push(res); ? ? ? ? ? ? ? ? ? ? ? ? //然后將當(dāng)前的操作符入符號棧 ? ? ? ? ? ? ? ? ? ? ? ? operStack.push(ch); ? ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ? //如果當(dāng)前的操作符的優(yōu)先級大于棧中的操作符, 就直接入符號棧. ? ? ? ? ? ? ? ? ? ? ? ? operStack.push(ch); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? }else { ? ? ? ? ? ? ? ? ? ? //如果為空直接入符號棧.. ? ? ? ? ? ? ? ? ? ? operStack.push(ch); // 1 + 3 ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } else { //如果是數(shù),則直接入數(shù)棧 ? ? ? ? ? ? ? ? //numStack.push(ch - 48); //? "1+3" '1' => 1 ? ? ? ? ? ? ? ? //分析思路 ? ? ? ? ? ? ? ? //1. 當(dāng)處理多位數(shù)時,不能發(fā)現(xiàn)是一個數(shù)就立即入棧,因?yàn)樗赡苁嵌辔粩?shù) ? ? ? ? ? ? ? ? //2. 在處理數(shù),需要向expression的表達(dá)式的index 后再看一位,如果是數(shù)就進(jìn)行掃描,如果是符號才入棧 ? ? ? ? ? ? ? ? //3. 因此我們需要定義一個變量 字符串,用于拼接 ? ? ? ? ? ? ? ? //處理多位數(shù) ? ? ? ? ? ? ? ? keepNum += ch; ? ? ? ? ? ? ? ? //如果ch已經(jīng)是expression的最后一位,就直接入棧 ? ? ? ? ? ? ? ? if (index == expression.length() - 1) { ? ? ? ? ? ? ? ? ? ? numStack.push(Integer.parseInt(keepNum)); ? ? ? ? ? ? ? ? }else{ ? ? ? ? ? ? ? ? ? ? //判斷下一個字符是不是數(shù)字,如果是數(shù)字,就繼續(xù)掃描,如果是運(yùn)算符,則入棧 ? ? ? ? ? ? ? ? ? ? //注意是看后一位,不是index++ ? ? ? ? ? ? ? ? ? ? if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))) { ? ? ? ? ? ? ? ? ? ? ? ? //如果后一位是運(yùn)算符,則入棧 keepNum = "1" 或者 "123" ? ? ? ? ? ? ? ? ? ? ? ? numStack.push(Integer.parseInt(keepNum)); ? ? ? ? ? ? ? ? ? ? ? ? //重要的!!!!!!, keepNum清空 ? ? ? ? ? ? ? ? ? ? ? ? keepNum = ""; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? //讓index + 1, 并判斷是否掃描到expression最后. ? ? ? ? ? ? index++; ? ? ? ? ? ? if (index >= expression.length()) { ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? //當(dāng)表達(dá)式掃描完畢,就順序的從 數(shù)棧和符號棧中pop出相應(yīng)的數(shù)和符號,并運(yùn)行. ? ? ? ? while(true) { ? ? ? ? ? ? //如果符號棧為空,則計算到最后的結(jié)果, 數(shù)棧中只有一個數(shù)字【結(jié)果】 ? ? ? ? ? ? if(operStack.isEmpty()) { ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? ? ? num1 = numStack.pop(); ? ? ? ? ? ? num2 = numStack.pop(); ? ? ? ? ? ? oper = operStack.pop(); ? ? ? ? ? ? res = numStack.cal(num1, num2, oper); ? ? ? ? ? ? numStack.push(res);//入棧 ? ? ? ? } ? ? ? ? //將數(shù)棧的最后數(shù),pop出,就是結(jié)果 ? ? ? ? int res2 = numStack.pop(); ? ? ? ? System.out.printf("表達(dá)式 %s = %d", expression, res2); ? ? } } //先創(chuàng)建一個棧,直接使用前面創(chuàng)建好 //定義一個 ArrayStack2 表示棧, 需要擴(kuò)展功能 class ArrayStack2 { ? ? private int maxSize; // 棧的大小 ? ? private int[] stack; // 數(shù)組,數(shù)組模擬棧,數(shù)據(jù)就放在該數(shù)組 ? ? private int top = -1;// top表示棧頂,初始化為-1 ? ? //構(gòu)造器 ? ? public ArrayStack2(int maxSize) { ? ? ? ? this.maxSize = maxSize; ? ? ? ? stack = new int[this.maxSize]; ? ? } ? ? //增加一個方法,可以返回當(dāng)前棧頂?shù)闹? 但是不是真正的pop ? ? public int peek() { ? ? ? ? return stack[top]; ? ? } ? ? //棧滿 ? ? public boolean isFull() { ? ? ? ? return top == maxSize - 1; ? ? } ? ? //??? ? ? public boolean isEmpty() { ? ? ? ? return top == -1; ? ? } ? ? //入棧-push ? ? public void push(int value) { ? ? ? ? //先判斷棧是否滿 ? ? ? ? if(isFull()) { ? ? ? ? ? ? System.out.println("棧滿"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? top++; ? ? ? ? stack[top] = value; ? ? } ? ? //出棧-pop, 將棧頂?shù)臄?shù)據(jù)返回 ? ? public int pop() { ? ? ? ? //先判斷棧是否空 ? ? ? ? if(isEmpty()) { ? ? ? ? ? ? //拋出異常 ? ? ? ? ? ? throw new RuntimeException("??眨瑳]有數(shù)據(jù)~"); ? ? ? ? } ? ? ? ? int value = stack[top]; ? ? ? ? top--; ? ? ? ? return value; ? ? } ? ? //顯示棧的情況[遍歷棧], 遍歷時,需要從棧頂開始顯示數(shù)據(jù) ? ? public void list() { ? ? ? ? if(isEmpty()) { ? ? ? ? ? ? System.out.println("???,沒有數(shù)據(jù)~~"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? //需要從棧頂開始顯示數(shù)據(jù) ? ? ? ? for(int i = top; i >= 0 ; i--) { ? ? ? ? ? ? System.out.printf("stack[%d]=%d\n", i, stack[i]); ? ? ? ? } ? ? } ? ? //返回運(yùn)算符的優(yōu)先級,優(yōu)先級是程序員來確定, 優(yōu)先級使用數(shù)字表示 ? ? //數(shù)字越大,則優(yōu)先級就越高. ? ? public int priority(int oper) { ? ? ? ? if(oper == '*' || oper == '/'){ ? ? ? ? ? ? return 1; ? ? ? ? } else if (oper == '+' || oper == '-') { ? ? ? ? ? ? return 0; ? ? ? ? } else { ? ? ? ? ? ? return -1; // 假定目前的表達(dá)式只有 +, - , * , / ? ? ? ? } ? ? } ? ? //判斷是不是一個運(yùn)算符 ? ? public boolean isOper(char val) { ? ? ? ? return val == '+' || val == '-' || val == '*' || val == '/'; ? ? } ? ? //計算方法 ? ? public int cal(int num1, int num2, int oper) { ? ? ? ? int res = 0; // res 用于存放計算的結(jié)果 ? ? ? ? switch (oper) { ? ? ? ? ? ? case '+': ? ? ? ? ? ? ? ? res = num1 + num2; ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case '-': ? ? ? ? ? ? ? ? res = num2 - num1;// 注意順序 ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case '*': ? ? ? ? ? ? ? ? res = num1 * num2; ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case '/': ? ? ? ? ? ? ? ? res = num2 / num1; ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? default: ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? return res; ? ? } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot?實(shí)現(xiàn)動態(tài)添加定時任務(wù)功能
這篇文章主要介紹了SpringBoot?動態(tài)添加定時任務(wù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02Mybatis-Plus同時使用邏輯刪除和唯一索引的問題及解決辦法(報數(shù)據(jù)重復(fù)Duplicate entry的
在開發(fā)中,我們經(jīng)常會有邏輯刪除和唯一索引同時使用的情況,但當(dāng)使用mybatis plus時,如果同時使用邏輯刪除和唯一索引,會報數(shù)據(jù)重復(fù)Duplicate entry的問題,如何解決這個問題呢,小編給大家分享Mybatis-Plus同時使用邏輯刪除和唯一索引的問題及解決辦法,一起看看吧2023-11-11SpringBoot如何手寫一個starter并使用這個starter詳解
starter是SpringBoot中的一個新發(fā)明,它有效的降低了項(xiàng)目開發(fā)過程的復(fù)雜程度,對于簡化開發(fā)操作有著非常好的效果,下面這篇文章主要給大家介紹了關(guān)于SpringBoot如何手寫一個starter并使用這個starter的相關(guān)資料,需要的朋友可以參考下2022-12-12windows環(huán)境下java開發(fā)工具maven的安裝教程圖解
Maven是一個項(xiàng)目管理和綜合工具。Maven提供了開發(fā)人員構(gòu)建一個完整的生命周期框架。這篇文章主要介紹了windows環(huán)境下java開發(fā)工具maven的安裝,非常不錯對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07SpringBoot如何使用p6spy監(jiān)控數(shù)據(jù)庫
這篇文章主要介紹了SpringBoot如何使用p6spy監(jiān)控數(shù)據(jù)庫問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Java使用PreparedStatement接口及ResultSet結(jié)果集的方法示例
這篇文章主要介紹了Java使用PreparedStatement接口及ResultSet結(jié)果集的方法,結(jié)合實(shí)例形式分析了PreparedStatement接口及ResultSet結(jié)果集的相關(guān)使用方法與操作注意事項(xiàng),需要的朋友可以參考下2018-07-07