棧、隊列及優先級隊列


整體把握

數組、鏈表、樹等等都適用於數據庫應用中作數據記錄,常用來記錄對應於現實世界的數據;而棧、隊列及優先級隊列更多地是作為程序員的工具來使用(用最合適的工具干活),以簡化某些程序操作。

棧、隊列及優先級隊列都可以使用數組鏈表來實現,優先級隊列通常使用堆實現。

在棧、隊列及優先級隊列中,訪問是受限制的,在某一時刻只有某一個特定的數據項可以被讀取或刪除。


應用:單詞逆序;解析源代碼時檢驗括號匹配;解析算術表達式;棧操作還嵌入在微處理器中,比如當調用一個方法時返回值和參數壓入棧,方法結束時,那些數據出棧。

解析算術表達式:

算術表達式求值通常都是先轉換為后綴表達式,再求后綴表達式的值;在中綴表表達式轉換為后綴表達式以及求后綴表達式的值的過程里,棧都是很有用的工具。

中綴表表達式 后綴表達式
((A+B)*C)-D AB+C*D-
A+B*(C-D/(E+F)) ABCDEF+/-*+

 

 

 

 

轉換后綴表達式規則:操作數不入棧,操作符入棧,在適當的時候出棧,比如中綴表達式1+2*3-5=,解析為后綴表達式過程如下表所示

步數 讀表達式 var 棧  備注
第一步 1 1    
第二步 1+ 1 +  
第三步 1+2 12 +  
第四步 1+2* 12 +*  
第五步 1+2*3 123 +*  
第六步 1+2*3- 123*+ - 讀到-時把*出棧,把+也出棧
第七步 1+2*3-5 123*+5 -  
第八步 1+2*3-5= 123*+5-   讀到=時把-出棧

 

 

 

 

 

 

 

 

 

 

 

 后綴表達式求值規則:操作數入棧、遇到操作符從棧中提出兩個操作數執行計算,結果入棧,計算123*+5-的值如下表所示

步數 讀表達式 棧 
第一步 1 1
第二步 12 12
第三步 123 123
第四步 123* 16
第五步 123*+ 7
第六步 123*+5 75
第七步 123*+5- 2

 

 

 

 

 

 

 

 

 

 

實現

數組實現,棧內有一個top記錄棧頂的數據頂,插入++top,刪除top--
單鏈表實現,push()對應insertFisrt(),pop()對應deleteFirst()

效率

入棧出棧O(1),也就是說,所耗的時間不依賴於棧中數據項的個數,棧不需要比較和移動操作。

代碼

package MyTest;

public class Stack {
    private int[] dataArr;
    private int initCapacity;
    private int top;

    public Stack(int initCapacity) {
        dataArr = new int[initCapacity];
        top = -1;
        this.initCapacity = initCapacity;
    }

    public void push(int element) {
        dataArr[++top] = element;
    }

    public int pop() {
        return dataArr[top--];
    }

    public int peek() {
        return dataArr[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public boolean isFull() {
        return top == initCapacity - 1;
    }
}

class MyTest {
    public static void main(String[] args) {
        Stack stack = new Stack(20);
        stack.push(200);
        stack.push(300);
        stack.push(404);
        stack.push(555);
        stack.push(606);

        System.out.print(stack.peek() + "  ");
        System.out.print(stack.peek() + "  \n");
        while (!stack.isEmpty()) {
            int pop = stack.pop();
            System.out.print(pop + "  ");
        }

        if (!stack.isEmpty()) {
            System.out.print(stack.peek());
        } else {
            System.out.println();
            System.out.print("Stack is empty");
        }
    }
}

class WordReverser {
    public static void main(String[] args) {
        String str = wordReverser("中華人民共和國");
        System.out.println(str);
    }

    private static String wordReverser(String str) {
        Stack stack = new Stack(20);
        for (int i = 0; i < str.length(); i++) {
            stack.push(str.charAt(i));
        }
        str = "";
        while (!stack.isEmpty()) {
            str += (char) stack.pop();
        }
        return str;
    }
}

class Compiler {
    private static String src1 = "c[d]";        // correct,正確的
    private static String src2 = "a{b[c]d}e";  // correct
    private static String src3 = "a{b(c]d}e";  // not correct; doesn't match
    private static String src4 = "a[b{c}d]e}"; // not correct; nothing matches final }
    private static String src5 = "a{b(c)";     // not correct; nothing mathches opening {
    private static Stack stack = new Stack(10);

    public static void main(String[] args) {
        /*
         * 結果有四種情況
         * 1、正確
         * 2、不匹配
         * 3、左括號多余,右括號多余
         */
        compile(src5);
    }

    public static void compile(String src) {
        char c = 0;
        for (int i = 0; i < src.length(); i++) {
            c = src.charAt(i);
            switch (c) {
                case '{':
                case '[':
                case '(':
                    stack.push(c);
                    break;
                case '}':
                case ']':
                case ')':
                    if (stack.isEmpty()) {
                        System.out.println("not correct; nothing matches final " + (char)c);
                        return;
                    } else {
                        int pop = stack.pop();
                        if (!(pop == '{' && c == '}' || pop == '[' && c == ']' || pop == '(' && c == ')')) {
                            System.out.println("not correct; doesn't match");
                            return;
                        }
                    }
            }
        }
        if (stack.isEmpty()) {
            System.out.println("correct");
        } else {
            System.out.println("not correct; nothing mathches opening " + (char) stack.pop());
        }
    }
}
View Code

隊列

應用

因特網數據包等待傳送;操作系統里有很多隊列,打印作業的打印隊列;文字處理軟件有一個容納鍵入內容的隊列,隊列保證了鍵入內容的順序不會改變。
隊列也可以用於模擬真實世界,比如模擬銀行排隊、飛機等待起飛。

實現

數組實現,通常的作法是通過移動隊頭隊尾的指針保持數據項的位置不變,這樣必須使用環繞式處理。
雙端鏈表實現,insert()對應insertLast(),remove對應deleteFirst()

效率

插入刪除數據項的時間復雜度都是O(1)


雙端隊列

頭尾都可以插入和刪除,比如可能有方法insertLeft()/insertRight、removeLeft()/removeRight()


優先級隊列 

優先級隊列其實就是有序隊列,有升序優先級隊列和降序優先級隊列;它允許訪問最小(最大)的數據項。

應用

在搶先式多任務操作系統中,程序排列在優先級隊列中,這樣優先級最高的程序就會先得到時間片運行。
很多情況下需要訪問具有最小關鍵字值的數據項,比如尋找最便宜的方法或最短的路徑去做某件事。

實現

除了可以快速訪問最小關鍵字值的數據項,優先級隊列還應該實現相當快的插入數據項,因此優先級隊列通常使用椎來實現。
數組實現1——>有序數組實現,不需要使用環繞指針,插入慢,刪除快
數組實現2——>無序數組實現,插入快,刪除慢,因為要尋找最小值
有序鏈表實現


免責聲明!

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



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