《資料結構與演算法之美》- 棧
《資料結構與演算法之美》- 棧
棧,在這裡說的是一種資料結構。
你還可能知道的棧
提到“棧”,做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;
}
}
}