1. 程式人生 > >《資料結構與演算法之美》- 棧

《資料結構與演算法之美》- 棧

《資料結構與演算法之美》- 棧

棧,在這裡說的是一種資料結構。

你還可能知道的棧

提到“棧”,做Java的同學還會想起Java記憶體模型中的“棧”,與之緊密關聯的還有一個名詞——堆,但是這裡,此棧非彼棧。

引用《深入理解Java虛擬機器》中有關棧的介紹

經常有人把Java記憶體區分為堆記憶體(Heap)和棧記憶體(Stack),這種分法比較粗糙,Java記憶體區域的劃分實際上遠比這複雜。這種劃分方式的流行只能說明大多數程式設計師最關注的、與物件記憶體分配關係最密切的記憶體區域是這兩塊。其中所指的“堆”筆者在後面專門講述,而所指的“棧”就是現在講的虛擬機器棧,或者說是虛擬機器棧中區域性變數部分。

區域性變量表存放了編譯可知的各種基本資料型別(boolean、byte、char、short、int、float、long、double)、物件引用(reference型別,它不等同於物件本身,可能是一個只想物件起始地址的引用指標,也可能是指向一個物件的控制代碼或其他與此物件相關的位置)和returnAddress型別(指向了一條位元組碼指令的地址)

說人話就是,Java記憶體結構中的一部分,執行緒私有,用來儲存指定的資料型別資料。

棧是什麼

棧是一種資料結構,它有自己的特點

  • 它是一種線性表,同為線性表的還有之前說到的陣列和連結串列

  • 它操作受限,具體表現在先進後出,後進先出,只能在一端進行資料的插入和刪除

基於以上兩點,大概就能勾勒出棧的模樣。

棧的應用

經常聽到有很多人抱怨說(也包括我~~~),如果知道這門課這麼重要,我當時拼死老命也要把它學好。

還記得當時看吳恩達的《machine learning》,在前幾節課裡展示瞭如何使用聚類演算法進行影象處理,如果使用增強學習演算法讓一個模型飛機飛起來

那麼,我們來看下棧有什麼應用

棧在表示式求值中的應用

給出一個表示式“3+5*8-6”,如果讓你算,想必難不倒你。

交給機器做,肯定也難不倒它,機器甚至可以做更加複雜的你做不到的運算。

但是機器底層是怎麼做的,如果不給定規則,它並不知道加減乘除是什麼,也不知道他們的優先順序順序。所以,這時候棧就排上了用場。

具體做法:

準備兩個棧,一個用來儲存需要運算的數字,一個用來儲存運算子號。

數字棧按照從左到右的順序入棧,符號棧也是如此,只是除此之外還多了一個規則限定。

當新入棧的符號優先順序比當前棧頂符號的優先順序高的時候,繼續入棧;當比棧頂符號優先順序低或者相同時,則取出當前棧頂符號,同時取出數字棧的運算元字進行運算,將運算後的結果壓棧,直至兩個棧元素全部彈出。

具體看專題中給出的過程圖

棧在括號匹配中的應用

給出一串“{(({[{{}}]}))}”,需要校驗這串表示式中是否能前後一一匹配。

沒錯,這個也可以利用棧的特性解決。

具體做法:

從左到右掃描表示式,對於左括號入棧,遇到右括號則取出當前棧頂元素,如果發現匹配,則取出棧頂元素繼續匹配。

當所有字串匹配完成,並且棧最後是空棧,說明字串可以正確匹配。

棧在瀏覽器前進後退中的應用

在瀏覽器中,我們可以通過前進後退回到自己想要的網頁。

這個功能也是可以通過棧來實現的,具體做法:

準備兩個棧,一個用於存放前進棧的網頁ID,一個用於存放後退棧的網頁ID。當需要前進的時候,從前進棧取出棧頂元素,並將該元素放入後退棧中;

當需要後退的時候,從後退棧取出棧頂元素,並將該元素放入前進棧中。

具體實現參見專案rome中的BackAndForwardUtil和BackAndForwardUtilDemo類

如何實現一個棧

採用連結串列介面實現一個棧結構


package com.jackie.algo.geek.time.chapter8_stack;

/**
 * @Author: Jackie
 */
public class Stack {
    private Node top = null;

    /**
     * 壓棧
     * @see com.jackie.algo.geek.time.chapter6_linkedlist.LinkedList 中的insertToHead方法和這裡的push思想類似
     *
     * |------|
     * | node | 上移後的top在這個位置
     * |------|
     * |   p  | 一開始top在這裡,經過node.next = top綁定了node和p關係後,又通過top = node,則將top上移
     * |------|
     * |  ... |
     * |------|
     *
     */
    public void push(int value) {
        Node node = new Node(value, null);

        if (top == null) {
            top = node;
        } else {
            node.next = top;
            top = node;
        }
    }
    /**
     * 出棧
     */
    public int pop() {
        if (top == null) {
            return -1;
        }
        int value = top.value;
        top = top.next;

        return value;
    }
    public void printAll() {
        Node p = top;
        while (p != null) {
            System.out.print(p.value + " ");
            p = p.next;
        }
        System.out.println();
    }
    public static class Node {
        private int value;

        private Node next;

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }
}