關於「棧」,我有乙個非常貼切的例子,就是一摞疊在一起的盤子。我們平時放盤子的時候,都是從下往上乙個乙個放;取的時候,我們也是從上往下乙個乙個地依次取,不能從中間任意抽出。後進者先出,先進者後出,這就是典型的「棧」結構。
從棧的操作特性上來看,棧是一種「操作受限」的線性表,只允許在一端插入和刪除資料。
我第一次接觸這種資料結構的時候,就對它存在的意義產生了很大的疑惑。因為我覺得,相比陣列和鍊錶,棧帶給我的只有限制,並沒有任何優勢。那我直接使用陣列或者鍊錶不就好了嗎?為什麼還要用這個「操作受限」的「棧」呢?
事實上,從功能上來說,陣列或鍊錶確實可以替代棧,但你要知道,特定的資料結構是對特定場景的抽象,而且,陣列或鍊錶暴露了太多的操作介面,操作上的確靈活自由,但使用時就比較不可控,自然也就更容易出錯。
當某個資料集合只涉及在一端插入和刪除資料,並且滿足後進先出、先進後出的特性,我們就應該首選「棧」這種資料結構。
從剛才棧的定義裡,我們可以看出,棧主要包含兩個操作,入棧和出棧,也就是在棧頂插入乙個資料和從棧頂刪除乙個資料。理解了棧的定義之後,我們來看一看如何用**實現乙個棧。
實際上,棧既可以用陣列來實現,也可以用鍊錶來實現。用陣列實現的棧,我們叫作順序棧,用鍊錶實現的棧,我們叫作鏈式棧。
不管是順序棧還是鏈式棧,我們儲存資料只需要乙個大小為 n 的陣列就夠了。在入棧和出棧過程中,只需要一兩個臨時變數儲存空間,所以空間複雜度是 o(1)。
注意,這裡儲存資料需要乙個大小為 n 的陣列,並不是說空間複雜度就是 o(n)。因為,這 n 個空間是必須的,無法省掉。所以我們說空間複雜度的時候,是指除了原本的資料儲存空間外,演算法執行還需要額外的儲存空間。
空間複雜度分析是不是很簡單?時間複雜度也不難。不管是順序棧還是鏈式棧,入棧、出棧只涉及棧頂個別資料的操作,所以時間複雜度都是 o(1)。
支援動態擴容的順序棧
如果要實現乙個支援動態擴容的棧,我們只需要底層依賴乙個支援動態擴容的陣列就可以了。當棧滿了之後,我們就申請乙個更大的陣列,將原來的資料搬移到新陣列中。
實際上,支援動態擴容的順序棧,我們平時開發中並不常用到。
入棧、出棧的時間複雜度:
對於出棧操作來說,我們不會涉及記憶體的重新申請和資料的搬移,所以出棧的時間複雜度仍然是 o(1)。但是,對於入棧操作來說,情況就不一樣了。當棧中有空閒空間時,入棧操作的時間複雜度為 o(1)。但當空間不夠時,就需要重新申請記憶體和資料搬移,所以時間複雜度就變成了 o(n)。
也就是說,對於入棧操作來說,最好情況時間複雜度是 o(1),最壞情況時間複雜度是 o(n)。那平均情況下的時間複雜度又是多少呢?
如果當前棧大小為 k,並且已滿,當再有新的資料要入棧時,就需要重新申請 2 倍大小的記憶體,並且做 k 個資料的搬移操作,然後再入棧。但是,接下來的 k-1 次入棧操作,我們都不需要再重新申請記憶體和搬移資料,所以這 k-1 次入棧操作都只需要乙個 ******-push 操作就可以完成。
你應該可以看出來,這 k 次入棧操作,總共涉及了 k 個資料的搬移,以及 k 次 ******-push 操作。將 k 個資料搬移均攤到 k 次入棧操作,那每個入棧操作只需要乙個資料搬移和乙個 ******-push 操作。以此類推,入棧操作的均攤時間複雜度就為 o(1)。
通過這個例子的實戰分析,也印證了前面講到的,均攤時間複雜度一般都等於最好情況時間複雜度。因為在大部分情況下,入棧操作的時間複雜度 o 都是 o(1),只有在個別時刻才會退化為 o(n),所以把耗時多的入棧操作的時間均攤到其他入棧操作上,平均情況下的耗時就接近 o(1)。
我們可以借助棧來檢查表示式中的括號是否匹配。
我們同樣簡化一下背景。我們假設表示式中只包含三種括號,圓括號 ()、方括號和花括號{},並且它們可以任意巢狀。比如,]}或[()]等都為合法格式,而()]或[(」匹配,則繼續掃瞄剩下的字串。如果掃瞄的過程中,遇到不能配對的右括號,或者棧中沒有資料,則說明為非法格式。
當所有的括號都掃瞄完成之後,如果棧為空,則說明字串為合法格式;否則,說明有未匹配的左括號,為非法格式。
棧是一種操作受限的資料結構,只支援入棧和出棧操作。後進先出是它最大的特點。棧既可以通過陣列實現,也可以通過鍊錶來實現。不管基於陣列還是鍊錶,入棧、出棧的時間複雜度都為 o(1)。除此之外,我們還講了一種支援動態擴容的順序棧.
CMake是什麼?有什麼用
cmake cmake是乙個跨平台的編譯 build 工具,可以用簡單的語句來描述所有平台的編譯過程。cmake能夠輸出各種各樣的makefile或者project檔案,能測試編譯器所支援的c 特性,類似unix下的automake。假如我們有乙個深度學習框架的部分工程列表,裡面有超過40個互相呼叫...
CMake是什麼?有什麼用?
原創 andrewzhou924 最後發布於2018 05 19 09 05 20 閱讀數 10989 收藏 發布於2018 05 19 09 05 20 分類專欄 學習筆記 展開cmake是乙個跨平台的編譯 build 工具,可以用簡單的語句來描述所有平台的編譯過程。cmake能夠輸出各種各樣的m...
nginx是什麼?有什麼用?
一句話概述 nginx是乙個使用c語言編寫的 開源 輕量級 高效能的web伺服器及反向 伺服器軟體,同時也是乙個 imap pop3 smtp 伺服器。由 igor sysoev 為俄羅斯訪問量第二的 rambler.ru 站點開發的,伊戈爾 賽索耶夫建立並於2004年首次公開發布,2011年成立同...