python 棧 python 棧的理解與應用

2021-10-11 22:34:09 字數 2096 閱讀 5263

如何理解「棧」?

關於「棧」,我有乙個非常貼切的例子,就是一摞疊在一起的盤子。我們平時放盤子的時候,都是從下往上乙個乙個放;取的時候,我們也是從上往下乙個乙個地依次取,不能從中間任意抽出。後進者先出,先進者後出,這就是典型的「棧」結構。

從棧的操作特性上來看,棧是一種「操作受限」的線性表,只允許在一端插入和刪除資料。

我第一次接觸這種資料結構的時候,就對它存在的意義產生了很大的疑惑。因為我覺得,相比陣列和鍊錶,棧帶給我的只有限制,並沒有任何優勢。那我直接使用陣列或者鍊錶不就好了嗎?為什麼還要用這個「操作受限」的「棧」呢?

事實上,從功能上來說,陣列或鍊錶確實可以替代棧,但你要知道,特定的資料結構是對特定場景的抽象,而且,陣列或鍊錶暴露了太多的操作介面,操作上的確靈活自由,但使用時就比較不可控,自然也就更容易出錯。

當某個資料集合只涉及在一端插入和刪除資料,並且滿足後進先出、先進後出的特性,我們就應該首選「棧」這種資料結構。

如何實現乙個「棧」?

從剛才棧的定義裡,我們可以看出,棧主要包含兩個操作,入棧和出棧,也就是在棧頂插入乙個資料和從棧頂刪除乙個資料。理解了棧的定義之後,我們來看一看如何用**實現乙個棧。

實際上,棧既可以用陣列來實現,也可以用鍊錶來實現。用陣列實現的棧,我們叫做順序棧,用鍊錶實現的棧,我們叫做鏈式棧。

不管是順序棧還是鏈式棧,我們儲存資料只需要乙個大小為 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)。除此之外,我們還講了一種支援動態擴容的順序棧.

python有棧嗎 Python 棧

棧抽象資料型別由下面的結構和操作定義。棧是元素的有序集合,新增操作與移除操作都發生在其頂端。棧的操作順序是 lifo,它支援以下操作 stack 建立乙個空棧。它不需要引數,且會返回乙個空棧。push item 將乙個元素新增到棧的頂端。它需要乙個引數 item,且無返回值。pop 將棧頂端的元素移...

用python實現棧 Python實現棧的方法

usr bin env python 定義乙個列表來模擬棧 stack def pu 出棧,用到了pop 函式 def popit if len stack 0 print cannot pop from an empty stack else print removed stack.pop 編歷棧...

python出棧的方法 Python實現棧的方法

定義乙個列表來模擬棧 stack def pu 出棧,用到了pop 函式 def popit if len stack 0 print cannot pop from an empty stack else print removed stack.pop 編歷棧 def viewstack prin...