棧的應用---括號的匹配和算術表達式的計算


  括號的匹配,就是給你一個表達式,比如a {b [c (d  + e) / 2  - f  ]  + 1}, 看看里面的括號是否匹配。怎么看呢?從左到右掃描表達式,遇到左括號{[(,就把它存起來,遇到其它字符,則忽略,遇到右括號時,把前面剛加進去的左括號取出來,看是否匹配。如果匹配,就繼續向下走,如果不匹配,就是不匹配了。存什么地方呢?假設存數組。拿a {b [c (d  + e) / 2  - f  ]  + 1} 舉例一下,從a開始,向后掃描,a是字符,忽略; { 是左括號,放到數組0位置;b是字符,忽略;[左括號,放到數組1位置;c是字符,忽略;(左括號,放到數組2的位置;d+e都是字符,忽略;)是右字符,這時就要從數組中拿出字符了,拿出哪一個呢?很顯然,是拿出位置2中的元素(,匹配嗎?()匹配,那繼續向下走,同時把2位置處的元素刪除;/2-f都是字符,忽略;]右括號,繼續從數組中拿出括號,這時要拿位置1處的元素,[,[]匹配,繼續向下走,同時把1位置處的元素刪除;+1都是字符,忽略;}右括號,繼續從數組中拿出括號,這時要拿位置0處的元素{,{}匹配,表達式沒有剩下字符了,整個表達式是匹配的。匹配過程中,可以看到左括號添加和取出,順序是相反的,添加的時候是0,1,2,取出的時候,是2,1,0. 這不就是棧嗎?重新描述一下表達式的匹配過程,遇到左括號,push()進棧,遇到右括號,pop()出棧,看pop()出來的元素是否和右括號匹配。

   {([都是左括號,push進棧;)是右括號,pop(), (出棧,()匹配;繼續 ,]是右括號,pop(),[出棧,[]匹配;繼續,}右括號,pop(),{出棧,{}匹配成功;整個表達式也成功了。

  再看幾個不匹配的表達式,比如{ [ ( ] ) },

   { [ (依次入棧,碰到],pop(), (出棧,(] 不匹配。再看一個 [ ( ) ] },

 

    [ (依次入棧,碰到), pop(), (出棧,() 匹配;碰到],pop(), [出棧,[]匹配;碰到},此時,棧為空,不能再pop()了,也就是沒有左括號和}匹配。再看{ [ ( ) ],

  { [ (依次入棧,) ]依次出棧,都匹配,但是棧中還剩余一個{,也就是沒有右括號和它匹配。

   經過上面的分析,括號匹配的實現也有點清晰了。創建一個棧,從左右向掃描表達式,就是循環遍歷表達式,遇到左括號,調用push()方法入棧,遇到右括號,要先判斷棧是否為空,如果為空,那肯定沒有對應的左括號,也就不匹配,直接return,不用再循環了。如果棧不為空,調用pop()方法,彈出一個左括號,看是否匹配,如果不匹配,也是return,不用再循環了,如果匹配,再繼續循環。如果循環完成了,也是匹配的,但還要判斷棧是否為空,如果為空,整個表達式就是匹配的,如果棧不為空,整個表達式是不匹配的。

  創建棧,可以使用自己的實現,也可以使用Java提供的LinkedList類,LinkedList實現了棧的API

package dataStructuresAndAbstractions.stack;

import java.util.LinkedList;

public class BalanceChecker {
    public static boolean checkBalance(String expression){
        LinkedList<Character> openDelimiterStack = new LinkedList<>();

        int charCount = expression.length();
        boolean isBanlanced = true;
        int index = 0;
        char nextChar = ' ';

        while (isBanlanced && (index < charCount)){
            nextChar = expression.charAt(index);
            switch (nextChar){

                case '(':
                case '{':
                case '[':
                    openDelimiterStack.push(nextChar);
                    break;

                case ')':
                case ']':
                case '}':
                    if(openDelimiterStack.isEmpty()){
                        isBanlanced= false;
                    } else {
                        char delimiter = openDelimiterStack.pop();
                        isBanlanced = isPaired(delimiter, nextChar);
                    }
                    break;
            }
            index++;
        }


        if (!openDelimiterStack.isEmpty()){
            isBanlanced = false;
        }

        return isBanlanced;

    }

    private static boolean isPaired(char open, char close){
        return (open == '(' && close == ')') ||
                (open == '[' && close == ']') ||
                (open == '{' && close == '}');
    }

    public static void main(String[] args) {
        String expression = "a {b [c (d + e)/2 - f] + 1}";
        boolean isBalanced = BalanceChecker.checkBalance(expression);
        if (isBalanced)
            System.out.println(expression + " is balanced");
        else System.out.println(expression + " is not balanced");
    }
}

  計算帶有括號的算術表達式,比如"(1+((2+3)*(4*5)))", 實現的思路是,先創建兩個棧,一個是存放操作數字符,一個存放操作符字符,再從左到右循環遍歷字符串,忽略左括號,遇到數字,壓入到數字字符棧中,遇到操作符,壓入到操作符棧中,遇到右括號,彈出一個操作符和兩個操作數進行計算,計算完成后,再壓入到數字字符棧中,循環完畢,數字棧中只有一個數,這個數就是表達式的計算結果。忽略(,1壓入操作數棧,+壓入操作符棧。忽略((,2壓入操作數棧,+壓入操作符棧,3壓入操作數棧。

   此時遇到了右擴號,彈出2,3,和+,執行3+2,把結果5壓入數字棧

   繼續向下走,*入操作符棧,忽略(,4壓入操作數棧,*壓入操作符棧,5壓入操作數棧)))

   遇到了右擴號,彈出5,4,和*,計算4*5,得出20放入操作數棧中

   向下走,還是右括號,彈出20,5,和*,把20*5的結果100,放入到操作數棧中

  還剩最后一個右括號,再把100,1和+彈出,把結果101放到操作數棧中,

   至此,表達式遍歷完畢,操作符數棧中,只剩下一個數字,這個數字,就是表達式的計算結果。

import java.util.LinkedList;

public class StackEvaluate {
    public static void main(String[] args) {
        LinkedList<String> ops = new LinkedList<>();
        LinkedList<Double> vals = new LinkedList<>();
        String expression = "(1+((2+3)*(4*5)))";

        for (int i = 0; i < expression.length(); i++) {
            String s = expression.charAt(i) + "";
            if (s.equals("(")) {
                ;
            } else if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {
                ops.push(s);
            } else if (s.equals(")")) {
                String op = ops.pop();
                double v = vals.pop();

                if (op.equals("+")) {
                    v = vals.pop() + v;
                } else if (op.equals("-")) {
                    v = vals.pop() - v;
                } else if (op.equals("*")) {
                    v = vals.pop() * v;
                } else if (op.equals("/")) {
                    v = vals.pop();
                }

                vals.push(v);
            } else {
                vals.push(Double.parseDouble(s));
            }
        }

        System.out.println(vals.pop());
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM