《數據結構與算法之美》- 棧


棧,在這里說的是一種數據結構。

你還可能知道的棧

提到“棧”,做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;
        }
    }
}

具體參見項目rome

如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!如果您想持續關注我的文章,請掃描二維碼,關注JackieZheng的微信公眾號,我會將我的文章推送給您,並和您一起分享我日常閱讀過的優質文章。


免責聲明!

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



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