利用Java棧結(jié)構(gòu)實現(xiàn)計算器功能

一、定義

棧是一種線性表結(jié)構(gòu),棧結(jié)構(gòu)中有兩端,對棧的操作都是對棧的一端進(jìn)行操作的,那么被操作的一端稱為棧頂,另一端則為棧底。對棧的操作其實就是只有兩種,分別是入棧(也稱為壓棧)和出棧(也稱為彈棧)。入棧,將新元素壓入棧中,那么此時這個棧元素就成為了棧頂元素,棧深度相應(yīng)的+1。出棧,將棧中的棧頂元素彈出來,此時棧頂?shù)南乱粋€元素就會成為新的棧頂元素,棧深度也相應(yīng)的-1。根據(jù)入棧和出棧的規(guī)則,也可以得到棧數(shù)據(jù)的順序是后進(jìn)先出(LIFO,LAST IN FIRST OUT)的特性。棧結(jié)構(gòu)的效率是非常高的,因此無論棧中數(shù)據(jù)的量有多大,操作的也只有棧頂元素一個數(shù)據(jù),因此棧的時間復(fù)雜度為O(1),這里不考慮棧溢出擴(kuò)容的問題。棧結(jié)構(gòu)示意圖下圖:

image

二、棧的應(yīng)用場景

棧的數(shù)據(jù)接口在編程中的應(yīng)用是非常廣泛的,其中包括:

1、瀏覽器頁面的瀏覽記錄。我們在瀏覽器中瀏覽的頁面的時候后退和前進(jìn)能夠正確的跳轉(zhuǎn)到對應(yīng)的頁面,就是利用了棧的特性來實現(xiàn)的。

2、java虛擬機(jī)中棧的操作數(shù)棧也是利用棧實現(xiàn)的。java在編譯的時候講操作的代碼壓入操作數(shù)棧中,進(jìn)行運算時就將棧頂元素彈出來,然后進(jìn)行運算后將結(jié)果再壓進(jìn)操作數(shù)棧中。

3、計算器的實現(xiàn)。我們在計算的時候一般都是從左往右計算的,但是這種方式對于計算機(jī)是非常不友好的,它需要進(jìn)行大量的判斷才可以。但是利用棧以及一些算法就能輕松實現(xiàn)計算的功能。我們下面的例子也將會利用棧結(jié)構(gòu)來實現(xiàn)簡易的計算器的功能。

三、入棧和出棧

棧結(jié)構(gòu)可以使用數(shù)組結(jié)構(gòu)和鏈表結(jié)構(gòu)來實現(xiàn),因此不同的實現(xiàn)方式,入棧和出棧的實現(xiàn)方式也會有所區(qū)別?;跀?shù)組實現(xiàn)的棧的入棧和出棧操作實質(zhì)是在內(nèi)部維護(hù)了一個指針,這個指針指向的元素即為棧頂元素,入棧時講指針向上移動一位,相反地則向下移動一位?;阪湵淼臈>蜎]有了指針的概念。鏈表使用單向鏈表即可實現(xiàn)。鏈表的出棧和入棧實質(zhì)上維護(hù)的鏈表頭部元素。下面使用示意圖來簡單的演示一下兩種結(jié)構(gòu)的入棧和出棧的流程:

1、基于數(shù)組的入棧和出棧:

image

2.鏈表的入棧和出棧

image

四、代碼實現(xiàn)

1.數(shù)組

/**
 * 基于數(shù)組實現(xiàn)的棧
 */
public class ArrayStack<E> implements Stack<E> {

    private Object[] data;
    private int index = -1;
    private int deep;
    private static final int DEFAULT_CAPACITY = 1 << 4;

    public ArrayStack() {
        deep = DEFAULT_CAPACITY;
        data = new Object[deep];
    }

    public ArrayStack(int capacity) {
        if (capacity <= 0) {
            capacity = DEFAULT_CAPACITY;
        }
        deep = capacity;
        data = new Object[deep];
    }

    /**
     * 添加數(shù)據(jù),數(shù)組滿了就不添加
     * @param e 入棧元素
     * @return
     */
    @Override
    public E push(E e) {
        if (isFull()) {
            System.out.println("棧已滿");
            return null;
        }
        data[++index] = e;
        return e;
    }

    /**
     * 彈出元素
     * @return 棧頂元素
     */
    @Override
    public E pop() {
        if (isEmpty()) {
            System.out.println("棧為空");
            return null;
        }
        return (E) data[index--];
    }

    /**
     * 查看棧頂元素
     * @return
     */
    @Override
    public E peek() {
        if (isEmpty()) {
            System.out.println("棧為空");
            return null;
        }
        return (E) data[index];
    }

    /**
     * 棧深度
     * @return
     */
    @Override
    public int size() {
        return index + 1;
    }

    private boolean isEmpty() {
        return index <= -1;
    }

    private boolean isFull() {
        return deep == index + 1;
    }

2.鏈表

/**
 * 基于鏈表實現(xiàn)的棧
 * @param <E>
 */
public class LinkStack<E> implements Stack<E> {

    private Node<E> head;
    private int size;

    @Override
    public E push(E e) {
        Node<E> node = new Node<>(e);
        if (head == null) {
            head = node;
        }else {
            Node<E> n = head;
            head = node;
            head.next = n;
        }
        size++;
        return e;
    }

    @Override
    public E pop() {
        if (head == null) {
            return null;
        }
        E data = head.data;
        head = head.next;
        size--;
        return data;
    }

    @Override
    public E peek() {
        return head == null ? null : head.data;
    }

    @Override
    public int size() {
        return size;
    }

    private static class Node<E> {
        E data;
        Node<E> next;

        public Node(E e) {
            data = e;
        }
    }
}
/**
 * 棧結(jié)構(gòu)
 */
public interface Stack<E> {

    /**
     * 入棧
     * @param e 入棧元素
     * @return 入棧元素
     */
    E push(E e);

    /**
     * 將棧頂元素彈出
     * @return 棧頂元素
     */
    E pop();

    /**
     * 查看棧頂元素,該方法不會彈出棧頂元素
     * @return 棧頂元素
     */
    E peek();

    /**
     * 查看棧深度
     * @return 棧深度
     */
    int size();
}

五、應(yīng)用實例:簡易計算器

在進(jìn)入寫代碼之前需要知道的前置知識是:前綴表達(dá)式(也叫波蘭表達(dá)式),中綴表達(dá)式和后綴表達(dá)式(也叫逆波蘭表達(dá)式)。

前綴、中綴、后綴表達(dá)式是對表達(dá)式的不同記法,其區(qū)別在于運算符相對于操作數(shù)的位置不同,前綴表達(dá)式的運算符位于操作數(shù)之前,中綴和后綴同理

舉例:
  中綴表達(dá)式:1 + (2 + 3) × 4 - 5
  前綴表達(dá)式:- + 1 × + 2 3 4 5
  后綴表達(dá)式:1 2 3 + 4 × + 5 -

中綴表達(dá)式 中綴表達(dá)式是一種通用的算術(shù)或邏輯公式表示方法,操作符以中綴形式處于操作數(shù)的中間。中綴表達(dá)式是人們常用的算術(shù)表示方法。 雖然人的大腦很容易理解與分析中綴表達(dá)式,但對計算機(jī)來說中綴表達(dá)式卻是很復(fù)雜的,因此計算表達(dá)式的值時,通常需要先將中綴表達(dá)式轉(zhuǎn)換為前綴或后綴表達(dá)式,然后再進(jìn)行求值。對計算機(jī)來說,計算前綴或后綴表達(dá)式的值非常簡單。

我下面講解的例子中是利用后綴表達(dá)式的算法來實現(xiàn)的,因此,代碼中回涉及到 運算字符串轉(zhuǎn)中綴表達(dá)式,中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式的過程。

后綴表達(dá)式步驟

從左至右掃描表達(dá)式,遇到數(shù)字時,將數(shù)字壓入堆棧,遇到運算符時,彈出棧頂?shù)膬蓚€數(shù),用運算符對它們做相應(yīng)的計算(次頂元素 和 棧頂元素),并將結(jié)果入棧;重復(fù)上述過程直到表達(dá)式最右端,最后運算得出的值即為表達(dá)式的結(jié)果。

例如: (3+4)×5-6 對應(yīng)的后綴表達(dá)式就是 3 4 + 5 × 6 - , 針對后綴表達(dá)式求值步驟如下:

1.從左至右掃描,將3和4壓入堆棧;
  2.遇到+運算符,因此彈出4和3(4為棧頂元素,3為次頂元素),計算出3+4的值,得7,再將7入棧;
  3.將5入棧;
  4.接下來是×運算符,因此彈出5和7,計算出7×5=35,將35入棧;
  5.將6入棧;
  6.最后是-運算符,計算出35-6的值,即29,由此得出最終結(jié)果

根據(jù)上面的步驟,我們可以使用代碼來實現(xiàn):

  /**
     * 根據(jù)后綴表達(dá)式計算值
     * @param items 后綴表達(dá)式
     * @return 計算結(jié)果
     */
    public int calculate(List<String> items) {
        /**
         * 用于保存過程變量和操作符等
         */
        Stack<String> stack = new LinkStack<>();
        //便利
        for (String item : items) {
            //如果為數(shù)字,直接放入棧中
            if (item.matches("\\d+")) {
                stack.push(item);
            }else {
                //彈出棧頂元素進(jìn)行運算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res;
                switch (item) {
                    case "+" :
                        res = num1 + num2;
                        break;
                    case "-" :
                        res = num1 - num2;
                        break;
                    case "*" :
                        res = num1 * num2;
                        break;
                    case "/" :
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("非法的運算符:" + item);
                }
                //運算完將結(jié)果壓入棧中
                stack.push("" + res);
            }
        }
        //整個表達(dá)式掃描結(jié)束后,此時棧中只剩一個元素,該元素即為結(jié)算結(jié)果,從棧中彈出即可
        return Integer.parseInt(stack.pop());
    }

測試結(jié)果:

 public static void main(String[] args) {
        Calculator calculator = new Calculator();
        List<String> items = new ArrayList<>();
        items.add("3");
        items.add("4");
        items.add("+");
        items.add("5");
        items.add("*");
        items.add("6");
        items.add("-");
        System.out.println(calculator.calculate(items));
    }

//結(jié)果:29

雖然后面可以計算出表達(dá)式的最終結(jié)果,但是的實際的應(yīng)用中計算的表達(dá)式往往都是按照我們的計算習(xí)慣來書寫的(即中綴表達(dá)式,如(3+4)×5-6)。因此,想要正確的得到結(jié)果我們需要再多一個步驟,就是人們習(xí)慣的計算方式的中綴表達(dá)式轉(zhuǎn)換成對計算機(jī)友好的后綴表達(dá)式。具體步驟如下:

1)初始化兩個棧:運算符棧s1和儲存中間結(jié)果的棧s2;
  2)從左至右掃描中綴表達(dá)式;
  3)遇到操作數(shù)時,將其壓s2;
  4)遇到運算符時,比較其與s1棧頂運算符的優(yōu)先級:
    4.1)如果s1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
    4.2)否則,若優(yōu)先級比棧頂運算符的高,也將運算符壓入s1;
    4.3)否則,將s1棧頂?shù)倪\算符彈出并壓入到s2中,再次轉(zhuǎn)到(4-1)與s1中新的棧頂運算符相比較;

5)遇到括號時:
    5.1) 如果是左括號“(”,則直接壓入s1
    5.2) 如果是右括號“)”,則依次彈出s1棧頂?shù)倪\算符,并壓入s2,直到遇到左括號為止,此時將這一對括號丟棄
  6)重復(fù)步驟2至5,直到表達(dá)式的最右邊
  7)將s1中剩余的運算符依次彈出并壓入s2
  8)依次彈出s2中的元素并輸出,結(jié)果的逆序即為中綴表達(dá)式對應(yīng)的后綴表達(dá)式

具體代碼如下:

(一)、解析算式

  /**
     * 將表達(dá)式解析成List
     * @param expression 表達(dá)式
     * @return
     */
    private List<String> parseExpr(String expression) {
        char[] chars = expression.toCharArray();
        int len = chars.length;
        List<String> items = new ArrayList<>(len);
        int index = 0;
        while (index < len) {
            char c = chars[index];
            //數(shù)字
            if (c >= 48 && c <= 57) {
                String tmp = "";
                //操作數(shù)大于一位數(shù),主要是通過判斷下一位是否為數(shù)字
                while (index < chars.length && chars[index] >= 48 && chars[index] <= 57) {
                    tmp += chars[index];
                    index++;
                }
                items.add(tmp);
            }else {
                items.add(c + "");
                index++;
            }
        }
        return items;
    }

(二)、獲取運算符的優(yōu)先級

  /**
     * 獲取運算符的優(yōu)先級,數(shù)字越大優(yōu)先級越大
     * @param operateChar 運算符
     * @return 優(yōu)先級
     */
    private int priority(String operateChar) {
        if ("*".equals(operateChar) || "/".equals(operateChar)) {
            return 2;
        }else if ("+".equals(operateChar) || "-".equals(operateChar)) {
            return 1;
        }else {
            //throw new RuntimeException("非法的操作符:" + operateChar);
            return 0;
        }
    }

(三)、中綴轉(zhuǎn)后綴表達(dá)式

 /**
 * 1)初始化兩個棧:運算符棧operateStack和儲存中間結(jié)果的棧tmp;
 * 2)從左至右掃描中綴表達(dá)式;
 * 3)遇到操作數(shù)時,將其壓tmp;
 * 4)遇到運算符時,比較其與operateStack棧頂運算符的優(yōu)先級:
 *   4.1)如果operateStack為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
 *   4.2)否則,若優(yōu)先級比棧頂運算符的高,也將運算符壓入operateStack;
 *   4.3)否則,將operateStack棧頂?shù)倪\算符彈出并壓入到tmp中,再次轉(zhuǎn)到(4-1)與operateStack中新的棧頂運算符相比較;
 * 5)遇到括號時:
 *   5.1) 如果是左括號“(”,則直接壓入operateStack
 *   5.2) 如果是右括號“)”,則依次彈出operateStack棧頂?shù)倪\算符,并壓入tmp,直到遇到左括號為止,此時將這一對括號丟棄
 * 6)重復(fù)步驟2至5,直到表達(dá)式的最右邊
 * 7)將operateStack中剩余的運算符依次彈出并壓入tmp
 * 8)依次彈出tmp中的元素并輸出,結(jié)果的逆序即為中綴表達(dá)式對應(yīng)的后綴表達(dá)式
 * @param expr 中綴表達(dá)式
 * @return 后綴表達(dá)式
 */
public List<String> midfixToSuffix(String expr) {
    /**
     * 將表達(dá)式的操作數(shù)和運算符轉(zhuǎn)換成集合
     */
    List<String> items = parseExpr(expr);
    //操作數(shù)棧
    Stack<String> operateStack = new LinkStack<>();
    //臨時變量的保存集合,這里使用了List集合
    //如果用棧也可以實現(xiàn),但是需要在最后將彈出棧元素的逆序進(jìn)行運算
    //所以使用List集合避免了這個轉(zhuǎn)換的問題
    List<String> tmp = new ArrayList<>();
    //操作的位置
    int index = 0;
    //表達(dá)式長度
    int len = items.size();
    while (index < len) {
        String item = items.get(index);
        //遇到操作數(shù)時,將其壓tmp;
        if (item.matches("\\d+")) {
            tmp.add(item);
        }else if (item.equals("(")) {//如果是左括號“(”,則直接壓入operateStack
            operateStack.push(item);
        } else if (item.equals(")")) {//如果是右括號“)”,則依次彈出operateStack棧頂?shù)倪\算符,并壓入tmp,直到遇到左括號為止,此時將這一對括號丟棄
            while (!operateStack.peek().equals("(")) {
                tmp.add(operateStack.pop());
            }
            //直接彈出棧頂元素即可
            operateStack.pop();
        } else {//遇到運算符時,比較其與operateStack棧頂運算符的優(yōu)先級
            //如果operateStack為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
            if (operateStack.isEmpty() || "(".equals(operateStack.peek())) {
                operateStack.push(item);
            }else if (priority(item) > priority(operateStack.peek())) {//否則,若優(yōu)先級比棧頂運算符的高,也將運算符壓入operateStack;
                tmp.add(item);
            } else {//否則,將operateStack棧頂?shù)倪\算符彈出并壓入到tmp中,再次轉(zhuǎn)到(4-1)與operateStack中新的棧頂運算符相比較;
                while (!operateStack.isEmpty() && priority(item) <= priority(operateStack.peek())) {
                    tmp.add(operateStack.pop());
                }
                //將運算符壓入棧
                operateStack.push(item);
            }
        }
        //沒一輪結(jié)束需要將操作位置往后移動一位
        index++;
    }
    //解析結(jié)束后需要將剩下的棧元素全部彈出來放入到tmp中
    while (!operateStack.isEmpty()) {
        tmp.add(operateStack.pop());
    }
    return tmp;
}

(四)、計算結(jié)果

  /**
     * 根據(jù)后綴表達(dá)式計算值
     * @param items 后綴表達(dá)式
     * @return 計算結(jié)果
     */
    public int calculate(List<String> items) {
        /**
         * 用于保存過程變量和操作符等
         */
        Stack<String> stack = new LinkStack<>();
        //便利
        for (String item : items) {
            //如果為數(shù)字,直接放入棧中
            if (item.matches("\\d+")) {
                stack.push(item);
            }else {
                //彈出棧頂元素進(jìn)行運算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res;
                switch (item) {
                    case "+" :
                        res = num1 + num2;
                        break;
                    case "-" :
                        res = num1 - num2;
                        break;
                    case "*" :
                        res = num1 * num2;
                        break;
                    case "/" :
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("非法的運算符:" + item);
                }
                //運算完將結(jié)果壓入棧中
                stack.push("" + res);
            }
        }
        //整個表達(dá)式掃描結(jié)束后,此時棧中只剩一個元素,該元素即為結(jié)算結(jié)果,從棧中彈出即可
        return Integer.parseInt(stack.pop());
    }

(五)、測試

  public static void main(String[] args) {
        Calculator calculator = new Calculator();
        List<String> items = calculator.midfixToSuffix("(3+4)*5-6");
        System.out.println("后綴表達(dá)式為:" + items);
        int result = calculator.calculate(items);
        System.out.println("運算結(jié)果為: " + result);
    }

//后綴表達(dá)式為:[3, 4, +, 5, *, 6, -]
//運算結(jié)果為: 29

完整的代碼如下:

public class Calculator {

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        List<String> items = calculator.midfixToSuffix("(3+4)*5-6");
        System.out.println("后綴表達(dá)式為:" + items);
        int result = calculator.calculate(items);
        System.out.println("運算結(jié)果為: " + result);
    }

    /**
     * 1)初始化兩個棧:運算符棧operateStack和儲存中間結(jié)果的棧tmp;
     * 2)從左至右掃描中綴表達(dá)式;
     * 3)遇到操作數(shù)時,將其壓tmp;
     * 4)遇到運算符時,比較其與operateStack棧頂運算符的優(yōu)先級:
     *   4.1)如果operateStack為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
     *   4.2)否則,若優(yōu)先級比棧頂運算符的高,也將運算符壓入operateStack;
     *   4.3)否則,將operateStack棧頂?shù)倪\算符彈出并壓入到tmp中,再次轉(zhuǎn)到(4-1)與operateStack中新的棧頂運算符相比較;
     * 5)遇到括號時:
     *   5.1) 如果是左括號“(”,則直接壓入operateStack
     *   5.2) 如果是右括號“)”,則依次彈出operateStack棧頂?shù)倪\算符,并壓入tmp,直到遇到左括號為止,此時將這一對括號丟棄
     * 6)重復(fù)步驟2至5,直到表達(dá)式的最右邊
     * 7)將operateStack中剩余的運算符依次彈出并壓入tmp
     * 8)依次彈出tmp中的元素并輸出,結(jié)果的逆序即為中綴表達(dá)式對應(yīng)的后綴表達(dá)式
     * @param expr 中綴表達(dá)式
     * @return 后綴表達(dá)式
     */
    public List<String> midfixToSuffix(String expr) {
        /**
         * 將表達(dá)式的操作數(shù)和運算符轉(zhuǎn)換成集合
         */
        List<String> items = parseExpr(expr);
        //操作數(shù)棧
        Stack<String> operateStack = new LinkStack<>();
        //臨時變量的保存集合,這里使用了List集合
        //如果用棧也可以實現(xiàn),但是需要在最后將彈出棧元素的逆序進(jìn)行運算
        //所以使用List集合避免了這個轉(zhuǎn)換的問題
        List<String> tmp = new ArrayList<>();
        //操作的位置
        int index = 0;
        //表達(dá)式長度
        int len = items.size();
        while (index < len) {
            String item = items.get(index);
            //遇到操作數(shù)時,將其壓tmp;
            if (item.matches("\\d+")) {
                tmp.add(item);
            }else if (item.equals("(")) {//如果是左括號“(”,則直接壓入operateStack
                operateStack.push(item);
            } else if (item.equals(")")) {//如果是右括號“)”,則依次彈出operateStack棧頂?shù)倪\算符,并壓入tmp,直到遇到左括號為止,此時將這一對括號丟棄
                while (!operateStack.peek().equals("(")) {
                    tmp.add(operateStack.pop());
                }
                //直接彈出棧頂元素即可
                operateStack.pop();
            } else {//遇到運算符時,比較其與operateStack棧頂運算符的優(yōu)先級
                //如果operateStack為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
                if (operateStack.isEmpty() || "(".equals(operateStack.peek())) {
                    operateStack.push(item);
                }else if (priority(item) > priority(operateStack.peek())) {//否則,若優(yōu)先級比棧頂運算符的高,也將運算符壓入operateStack;
                    tmp.add(item);
                } else {//否則,將operateStack棧頂?shù)倪\算符彈出并壓入到tmp中,再次轉(zhuǎn)到(4-1)與operateStack中新的棧頂運算符相比較;
                    while (!operateStack.isEmpty() && priority(item) <= priority(operateStack.peek())) {
                        tmp.add(operateStack.pop());
                    }
                    //將運算符壓入棧
                    operateStack.push(item);
                }
            }
            //沒一輪結(jié)束需要將操作位置往后移動一位
            index++;
        }
        //解析結(jié)束后需要將剩下的棧元素全部彈出來放入到tmp中
        while (!operateStack.isEmpty()) {
            tmp.add(operateStack.pop());
        }
        return tmp;
    }

    /**
     * 獲取運算符的優(yōu)先級,數(shù)字越大優(yōu)先級越大
     * @param operateChar 運算符
     * @return 優(yōu)先級
     */
    private int priority(String operateChar) {
        if ("*".equals(operateChar) || "/".equals(operateChar)) {
            return 2;
        }else if ("+".equals(operateChar) || "-".equals(operateChar)) {
            return 1;
        }else {
            //throw new RuntimeException("非法的操作符:" + operateChar);
            return 0;
        }
    }

    /**
     * 將表達(dá)式解析成List
     * @param expression 表達(dá)式
     * @return
     */
    private List<String> parseExpr(String expression) {
        char[] chars = expression.toCharArray();
        int len = chars.length;
        List<String> items = new ArrayList<>(len);
        int index = 0;
        while (index < len) {
            char c = chars[index];
            //數(shù)字
            if (c >= 48 && c <= 57) {
                String tmp = "";
                //操作數(shù)大于一位數(shù),主要是通過判斷下一位是否為數(shù)字
                while (index < chars.length && chars[index] >= 48 && chars[index] <= 57) {
                    tmp += chars[index];
                    index++;
                }
                items.add(tmp);
            }else {
                items.add(c + "");
                index++;
            }
        }
        return items;
    }

    /**
     * 根據(jù)后綴表達(dá)式計算值
     * @param items 后綴表達(dá)式
     * @return 計算結(jié)果
     */
    public int calculate(List<String> items) {
        /**
         * 用于保存過程變量和操作符等
         */
        Stack<String> stack = new LinkStack<>();
        //便利
        for (String item : items) {
            //如果為數(shù)字,直接放入棧中
            if (item.matches("\\d+")) {
                stack.push(item);
            }else {
                //彈出棧頂元素進(jìn)行運算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res;
                switch (item) {
                    case "+" :
                        res = num1 + num2;
                        break;
                    case "-" :
                        res = num1 - num2;
                        break;
                    case "*" :
                        res = num1 * num2;
                        break;
                    case "/" :
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("非法的運算符:" + item);
                }
                //運算完將結(jié)果壓入棧中
                stack.push("" + res);
            }
        }
        //整個表達(dá)式掃描結(jié)束后,此時棧中只剩一個元素,該元素即為結(jié)算結(jié)果,從棧中彈出即可
        return Integer.parseInt(stack.pop());
    }

}

簡單的計算器基本已經(jīng)寫完了。如果你感興趣的話,可以將上面的代碼拿下來自己顯現(xiàn)更多的功能,比如說支持小數(shù),其他的運算,表達(dá)式中允許有空格等。這些功能實現(xiàn)起來是不難的,只要在上面的基礎(chǔ)上做一些改動即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容