數(shù)據(jù)結(jié)構(gòu)之棧應(yīng)用

棧在表達(dá)式求職中的應(yīng)用

分兩個(gè)棧:操作數(shù)棧和數(shù)字棧;
壓棧出棧規(guī)則:遍歷表達(dá)式

  • 如果是數(shù)字則直接壓入數(shù)字棧
  • 如果是操作符(加減乘除)則將該操作符與操作數(shù)棧的棧頂元素比較:優(yōu)先級(jí)高于棧頂元素則直接壓棧;優(yōu)先級(jí)小于等于棧頂元素則將棧頂元素出棧,并從數(shù)字棧中取兩個(gè)數(shù)字做操作,然后將結(jié)果壓回?cái)?shù)字棧(循環(huán)此過程直至操作數(shù)棧為空或者當(dāng)前操作數(shù)比棧頂元素優(yōu)先級(jí)高)。
  • 遍歷完之后,要看操作數(shù)棧是否為空,為空則結(jié)束,并從數(shù)字棧中取出結(jié)果;不為空,則操作數(shù)棧出棧且從數(shù)字棧中取兩個(gè)數(shù)字操作并將結(jié)果壓入棧,循環(huán)如此操作。

進(jìn)階:上面只考慮有操作數(shù)和數(shù)字的情況,沒有考慮括號(hào)的情況
如果考慮括號(hào),其實(shí)處理思路是差不多的:

  • 把右擴(kuò)號(hào))當(dāng)成優(yōu)先級(jí)最高的,當(dāng))從操作數(shù)棧出棧時(shí),還要再連續(xù)出棧兩個(gè)操作數(shù):一個(gè)運(yùn)算符一個(gè)左括號(hào),錯(cuò)了;是要一個(gè)一個(gè)操作數(shù)出棧,直至遇到左括號(hào)
  • 左括號(hào)(的優(yōu)先級(jí),定義為和)一樣,不行,其他操作符遇到(就會(huì)讓(出棧,定義為最低級(jí)別也不行,(要入棧的時(shí)候會(huì)讓棧中的操作符全部出棧。所以左括號(hào)要特殊處理,(的優(yōu)先級(jí)定義為最低,但是入棧的時(shí)候直接入

java實(shí)現(xiàn)如下:

import java.util.Stack;
/**
 * 描述:
 * 給定一個(gè)運(yùn)算式,計(jì)算其結(jié)果
 * 這里只是為了演示棧的使用,所以可以將輸入簡化為一個(gè)字符串?dāng)?shù)組,假定字符串要么是數(shù)字,要么是操作運(yùn)算符(加減乘除),要么是小括號(hào)。不用自己去解析了
 *
 * @author zzz
 * @date 2018/11/14
 */
public class CalculateOperator {

    public static void main(String[] args) {
//        String[] input = new String[]{"(", "(", "1", "-", "2", ")", "*", "(", "3", "-", "5", ")", "+", "4", ")", "/", "2"};

        String[] input = new String[]{"(","5","+","(","1","+","2",")","*","(","3","-","5",")",")","*","2"};

        System.out.println(input.length);

        CalculateOperator co = new CalculateOperator();
        System.out.println(co.calculateOperator(input));
    }

    public int calculateOperator(String[] input) {
        if (input == null || input.length == 0) {
            return 0;
        }

        Stack<String> operateStack = new Stack<>();
        Stack<Integer> digitStack = new Stack<>();

        for (String s : input) {
            if (isDigit(s)) {
                //數(shù)字直接入數(shù)字棧
                digitStack.push(Integer.parseInt(s));
            } else if ("(".equals(s)) {
                operateStack.push(s);
            } else {
                while (true) {
                    if (!operateStack.empty()) {
                        int levelMinus = operateLevel(s) - operateLevel(operateStack.peek());
                        if (levelMinus > 0) {
                            //當(dāng)前操作符優(yōu)先級(jí)高于棧頂操作符則直接入棧
                            operateStack.push(s);
                            break;
                        } else {
                            //否則,將棧頂操作符出棧并取兩個(gè)數(shù)字運(yùn)算,結(jié)果入數(shù)字棧;循環(huán)此過程
                            popCalculatePush(operateStack, digitStack);
                        }
                    } else {
                        operateStack.push(s);
                        break;
                    }
                }
            }
        }

        //處理?xiàng)V袣堄嗟牟僮鞣?        while (!operateStack.empty()) {
            popCalculatePush(operateStack, digitStack);
        }

        return digitStack.pop();
    }

    private void popCalculatePush(Stack<String> operateStack, Stack<Integer> digitStack) {
        String operator = operateStack.pop();
        if (")".equals(operator)) {
            //需要再出棧一個(gè)操作符和(左括號(hào) bug
            //注意:不一定一個(gè)操作符連著一個(gè)左括號(hào),右括號(hào)與左括號(hào)中間可能隔著多個(gè)運(yùn)算符,自己運(yùn)算下上面的第二個(gè)input就知道了
            //需要一直出棧知道遇到左括號(hào)(
            operator = operateStack.pop();
            while(!"(".equals(operator) && !operateStack.empty()){
                int y = digitStack.pop();
                int x = digitStack.pop();
                int calRes = calculate(x, y, operator);
                digitStack.push(calRes);

                operator = operateStack.pop();
            }

        } else {
            int y = digitStack.pop();
            int x = digitStack.pop();
            int calRes = calculate(x, y, operator);
            digitStack.push(calRes);
        }
    }

    private int calculate(int x, int y, String operator) {
        switch (operator) {
            case "+":
                return x + y;
            case "-":
                return x - y;
            case "*":
                return x * y;
            case "/":
                return x / y;
            default:
                return 0;
        }
    }

    private boolean isDigit(String str) {
        try {
            int digit = Integer.parseInt(str);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private int operateLevel(String s) {
        switch (s) {
            case "+":
            case "-":
                return 1;
            case "*":
            case "/":
                return 2;
            case ")":
                return 3;
            default:
                return 0;
        }
    }
}
棧在括號(hào)匹配中的應(yīng)用

各種括號(hào)組成的字符串:[],(),{}, 判斷字符串的括號(hào)使用是否是合法格式
舉例:{[()]}是合法的,{[}()]不合法
可以用一個(gè)棧就可以判斷:左括號(hào)直接入棧,遇到右括號(hào)直接從出棧一個(gè)符號(hào),如果與右括號(hào)類型匹配則繼續(xù),否則為非法格式;最后遍歷完棧為空則合法,棧非空則非法

java實(shí)現(xiàn)如下:

/**
 * 描述:
 * 各種括號(hào)組成的字符串:[],(),{}, 判斷字符串的括號(hào)使用是否是合法格式?
 * 舉例:{[()]}是合法的,{[}()]不合法
 *
 * @author zzz
 * @date 2018/11/14
 */
public class BracketMatch {

    private static final List<Character> leftBracket = Arrays.asList('(','{','[');

    private static final Map<Character,Character> pairs = new HashMap<>();

    static {
        pairs.put('(',')');
        pairs.put('[',']');
        pairs.put('{','}');
    }

    public static void main(String[] args) {
//        String s = "{[()]}[]";
        String s = "{[}()]";
        BracketMatch bracketMatch = new BracketMatch();
        System.out.println(bracketMatch.isBracketMatch(s));
    }

    public boolean isBracketMatch(String s) {
        if (s == null || s.length() == 0) {
            return true;
        }
        Stack<Character> stack = new Stack<>();
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(leftBracket.contains(c)){
                stack.push(c);
            } else {
                if(stack.empty()){
                    return false;
                } else {
                    char cPop = stack.pop();
                    boolean isMatch = isLeftRightMatch(cPop, c);
                    if(!isMatch){
                        return false;
                    }
                }
            }
        }

        return stack.empty();
    }

    private boolean isLeftRightMatch(char left, char right){
        if(pairs.get(left) == right){
            return true;
        }
        return false;
    }
}
棧在瀏覽器前進(jìn)、后退、跳轉(zhuǎn)新頁面中的操作

兩個(gè)棧:一個(gè)前進(jìn)棧X,一個(gè)后退棧Y

  • 前進(jìn)時(shí):從后退棧Y中出棧一個(gè)步驟并入棧到前進(jìn)棧X中
  • 后退時(shí):從前進(jìn)棧X中出棧一個(gè)步驟并入棧到后退棧Y中
  • 跳轉(zhuǎn)新頁面:清空后退棧Y,并將新步驟入前進(jìn)棧X

java代碼如下:

/**
 * 描述:
 *  棧實(shí)現(xiàn)瀏覽器前進(jìn)、后退、跳轉(zhuǎn)新頁面中的操作
 * @author zzz
 * @date 2018/11/14
 */
public class BrowserForwardOrBack {

    private Stack<Integer> stackX = new Stack<>();

    private Stack<Integer> stackY = new Stack<>();

    public static void main(String[] args) throws Exception{
        BrowserForwardOrBack bfob = new BrowserForwardOrBack();
        bfob.newPage(1);
        bfob.newPage(2);
        bfob.newPage(3);
        bfob.currentPage();//3

        bfob.back();
        bfob.back();
        bfob.forward();
        bfob.currentPage(); //2

        bfob.newPage(4);
        bfob.back();
        bfob.back();
        bfob.forward();
        bfob.currentPage();//2
    }

    public void currentPage(){
        if(!stackX.empty()){
            System.out.println(stackX.peek());
            return;
        }
        System.out.println("current page is not exist");
    }

    /**
     * Y-->X
     * @return
     * @throws Exception
     */
    public boolean forward() throws  Exception{

        if(stackY.empty()){
            throw new Exception("cannot forward");
        }

        stackX.push(stackY.pop());
        return true;
    }

    /**
     * X-->Y
     * @return
     */
    public boolean back() throws Exception{
        if(stackX.empty()){
            throw new Exception("cannot back");
        }

        stackY.push(stackX.pop());
        return true;
    }

    /**
     *
     * @param pageIndex 新頁面的標(biāo)識(shí),這里直接用數(shù)字表示
     * @return
     */
    public void newPage(int pageIndex){

        //清空stackY
        stackY.clear();

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

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