08 | 栈:如何实现浏览器的前进和后退功能?
棧
后進(jìn)者先出,先進(jìn)者后出,這就是典型的“?!苯Y(jié)構(gòu)。棧是一種“操作受限”的線性表,只允許在一端插入和刪除數(shù)據(jù)。
為什么要使用到“棧”這種操作受限的數(shù)據(jù)結(jié)構(gòu)?
事實(shí)上,從功能上來說,數(shù)組或鏈表確實(shí)可以替代棧,但你要知道,特定的數(shù)據(jù)結(jié)構(gòu)是對(duì)特定場(chǎng)景的抽象,而且,數(shù)組或鏈表暴露了太多的操作接口,操作上的確靈活自由,但使用時(shí)就比較不可控,自然也就更容易出錯(cuò)。
當(dāng)某個(gè)數(shù)據(jù)集合只涉及在一端插入和刪除數(shù)據(jù),并且滿足后進(jìn)先出、先進(jìn)后出的特性,這時(shí)我們就應(yīng)該首選“?!边@種數(shù)據(jù)結(jié)構(gòu)。
如何實(shí)現(xiàn)一個(gè)棧?
- 棧既可以用數(shù)組來實(shí)現(xiàn),也可以用鏈表來實(shí)現(xiàn)。
- 用數(shù)組實(shí)現(xiàn)的棧,我們叫作順序棧,
- 用鏈表實(shí)現(xiàn)的棧,我們叫作鏈?zhǔn)綏?/li>
順序棧的實(shí)現(xiàn):
// 基于數(shù)組實(shí)現(xiàn)的順序棧 public class ArrayStack {private String[] items; // 數(shù)組private int count; // 棧中元素個(gè)數(shù)private int n; //棧的大小// 初始化數(shù)組,申請(qǐng)一個(gè)大小為n的數(shù)組空間public ArrayStack(int n) {this.items = new String[n];this.n = n;this.count = 0;}// 入棧操作public boolean push(String item) {// 數(shù)組空間不夠了,直接返回false,入棧失敗。if (count == n) return false;// 將item放到下標(biāo)為count的位置,并且count加一items[count] = item;++count;return true;}// 出棧操作public String pop() {// 棧為空,則直接返回nullif (count == 0) return null;// 返回下標(biāo)為count-1的數(shù)組元素,并且棧中元素個(gè)數(shù)count減一String tmp = items[count-1];--count;return tmp;} }棧操作的復(fù)雜度分析
存儲(chǔ)數(shù)據(jù)只需要一個(gè)大小為 n 的數(shù)組就夠了。在入棧和出棧過程中,只需要一兩個(gè)臨時(shí)變量存儲(chǔ)空間,所以空間復(fù)雜度是 O(1);
入棧、出棧只涉及棧頂個(gè)別數(shù)據(jù)的操作,所以時(shí)間復(fù)雜度都是 O(1);
如何實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)容的順序棧?
動(dòng)態(tài)擴(kuò)容的數(shù)組:當(dāng)數(shù)組空間不夠時(shí),我們就重新申請(qǐng)一塊更大的內(nèi)存,將原來數(shù)組中數(shù)據(jù)統(tǒng)統(tǒng)拷貝過去。這樣就實(shí)現(xiàn)了一個(gè)支持動(dòng)態(tài)擴(kuò)容的數(shù)組;要實(shí)現(xiàn)一個(gè)支持動(dòng)態(tài)擴(kuò)容的棧,我們只需要底層依賴一個(gè)支持動(dòng)態(tài)擴(kuò)容的數(shù)組就可以了。當(dāng)棧滿了之后,我們就申請(qǐng)一個(gè)更大的數(shù)組,將原來的數(shù)據(jù)搬移到新數(shù)組中
棧的應(yīng)用
函數(shù)調(diào)用
操作系統(tǒng)給每個(gè)線程分配了一塊獨(dú)立的內(nèi)存空間,這塊內(nèi)存被組織成“棧”這種結(jié)構(gòu), 用來存儲(chǔ)函數(shù)調(diào)用時(shí)的臨時(shí)變量。每進(jìn)入一個(gè)函數(shù),就會(huì)將臨時(shí)變量作為一個(gè)棧幀入棧,當(dāng)被調(diào)用函數(shù)執(zhí)行完成,返回之后,將這個(gè)函數(shù)對(duì)應(yīng)的棧幀出棧;
代碼示例:
int main() {int a = 1; int ret = 0;int res = 0;ret = add(3, 5);res = a + ret;printf("%d", res);reuturn 0; }int add(int x, int y) {int sum = 0;sum = x + y;return sum; }編譯器通過棧實(shí)現(xiàn)求值表達(dá)式的求值
四則運(yùn)算法則:34+13*9+44-12/3
編譯器就是通過兩個(gè)棧來實(shí)現(xiàn)的。其中一個(gè)保存操作數(shù)的棧,另一個(gè)是保存運(yùn)算符的棧。我們從左向右遍歷表達(dá)式,當(dāng)遇到數(shù)字,我們就直接壓入操作數(shù)棧;當(dāng)遇到運(yùn)算符,就與運(yùn)算符棧的棧頂元素進(jìn)行比較;如果比運(yùn)算符棧頂元素的優(yōu)先級(jí)高,就將當(dāng)前運(yùn)算符壓入棧;如果比運(yùn)算符棧頂元素的優(yōu)先級(jí)低或者相同,從運(yùn)算符棧中取棧頂運(yùn)算符,從操作數(shù)棧的棧頂取 2 個(gè)操作數(shù),然后進(jìn)行計(jì)算,再把計(jì)算完的結(jié)果壓入操作數(shù)棧,繼續(xù)比較;
如何實(shí)現(xiàn)瀏覽器的后退和前進(jìn)功能?
- 定義兩個(gè)棧X和Y,將首次瀏覽的頁面壓入棧X,當(dāng)點(diǎn)擊后退按鈕時(shí),再依次從棧X中出棧,并將出棧的依次壓入棧Y,當(dāng)點(diǎn)擊前進(jìn)時(shí),就從Y中取出數(shù)據(jù)放入X中;
- 當(dāng)X中沒有數(shù)據(jù)時(shí),表示頁面不可后退,當(dāng)Y中沒有數(shù)據(jù)時(shí)表示頁面不可前進(jìn);
- 當(dāng)跳轉(zhuǎn)了新的頁面,新的頁面壓入棧X中,同時(shí)需要清空棧Y,也即當(dāng)前頁面不可以前進(jìn)了;
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的08 | 栈:如何实现浏览器的前进和后退功能?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch搭建LSTM神经网络预测电
- 下一篇: 各大浏览器兼容性报告